aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-05-02 15:13:49 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-05-02 15:14:36 +0200
commit44ca7e31ee9365a72cd17ecd335ec4d0161420a9 (patch)
treec03b4f8263b41986b6f5d4ac9c6e35e371e98a33 /src/qml
parent580fa7dc88aae23053e44ffa335a15f6af112a20 (diff)
parent325e6305b418ffe1dfb9a36c2516c6a8a3de5733 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h5
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h59
-rw-r--r--src/qml/compiler/qv4codegen.cpp83
-rw-r--r--src/qml/compiler/qv4compileddata_p.h6
-rw-r--r--src/qml/compiler/qv4compiler.cpp1
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp22
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h3
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp65
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h60
-rw-r--r--src/qml/configure.json87
-rw-r--r--src/qml/jit/jit.pri31
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp4
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h9
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp4
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h2
-rw-r--r--src/qml/jit/qv4baselinejit.cpp68
-rw-r--r--src/qml/jit/qv4baselinejit_p.h63
-rw-r--r--src/qml/jit/qv4blockscheduler.cpp208
-rw-r--r--src/qml/jit/qv4blockscheduler_p.h155
-rw-r--r--src/qml/jit/qv4domtree.cpp436
-rw-r--r--src/qml/jit/qv4domtree_p.h136
-rw-r--r--src/qml/jit/qv4graph.cpp103
-rw-r--r--src/qml/jit/qv4graph_p.h146
-rw-r--r--src/qml/jit/qv4graphbuilder.cpp1683
-rw-r--r--src/qml/jit/qv4graphbuilder_p.h298
-rw-r--r--src/qml/jit/qv4ir.cpp382
-rw-r--r--src/qml/jit/qv4ir_p.h228
-rw-r--r--src/qml/jit/qv4loopinfo.cpp199
-rw-r--r--src/qml/jit/qv4loopinfo_p.h159
-rw-r--r--src/qml/jit/qv4lowering.cpp200
-rw-r--r--src/qml/jit/qv4lowering_p.h107
-rw-r--r--src/qml/jit/qv4mi.cpp251
-rw-r--r--src/qml/jit/qv4mi_p.h627
-rw-r--r--src/qml/jit/qv4miblockset_p.h291
-rw-r--r--src/qml/jit/qv4node.cpp215
-rw-r--r--src/qml/jit/qv4node_p.h626
-rw-r--r--src/qml/jit/qv4operation.cpp770
-rw-r--r--src/qml/jit/qv4operation_p.h567
-rw-r--r--src/qml/jit/qv4runtimesupport_p.h255
-rw-r--r--src/qml/jit/qv4schedulers.cpp912
-rw-r--r--src/qml/jit/qv4schedulers_p.h162
-rw-r--r--src/qml/jit/qv4tracingjit.cpp91
-rw-r--r--src/qml/jsapi/qjsengine.cpp36
-rw-r--r--src/qml/jsapi/qjsengine.h3
-rw-r--r--src/qml/jsapi/qjsvalue.cpp6
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp13
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h20
-rw-r--r--src/qml/jsruntime/qv4function.cpp36
-rw-r--r--src/qml/jsruntime/qv4function_p.h25
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4global_p.h60
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp16
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp16
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp13
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp13
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h2
-rw-r--r--src/qml/jsruntime/qv4math_p.h27
-rw-r--r--src/qml/jsruntime/qv4object_p.h2
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp26
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp48
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h8
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp73
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp189
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h2
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h2
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/ftw/ftw.pri4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp54
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h (renamed from src/qml/types/qqmlmodelsmodule_p.h)34
-rw-r--r--src/qml/qml/ftw/qstringhash.cpp168
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h69
-rw-r--r--src/qml/qml/qqml.h17
-rw-r--r--src/qml/qml/qqmlbinding.cpp6
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp139
-rw-r--r--src/qml/qml/qqmlengine.h7
-rw-r--r--src/qml/qml/qqmlengine_p.h14
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp36
-rw-r--r--src/qml/qml/qqmlmetatype_p.h13
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h19
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlprivate.h5
-rw-r--r--src/qml/qml/qqmlproperty.cpp4
-rw-r--r--src/qml/qml/qqmltype.cpp82
-rw-r--r--src/qml/qml/qqmltype_p.h29
-rw-r--r--src/qml/qml/qqmltype_p_p.h1
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp181
-rw-r--r--src/qml/qtqmlglobal.h2
-rw-r--r--src/qml/types/qqmldelegatecomponent.cpp300
-rw-r--r--src/qml/types/qqmldelegatecomponent_p.h155
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp3540
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h248
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h450
-rw-r--r--src/qml/types/qqmlinstantiator.cpp509
-rw-r--r--src/qml/types/qqmlinstantiator_p.h119
-rw-r--r--src/qml/types/qqmlinstantiator_p_p.h98
-rw-r--r--src/qml/types/qqmlitemmodels.qdoc110
-rw-r--r--src/qml/types/qqmlitemselectionmodel.qdoc239
-rw-r--r--src/qml/types/qqmllistmodel.cpp2900
-rw-r--r--src/qml/types/qqmllistmodel_p.h208
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h428
-rw-r--r--src/qml/types/qqmllistmodelworkeragent.cpp177
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h140
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp123
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp431
-rw-r--r--src/qml/types/qqmlobjectmodel_p.h194
-rw-r--r--src/qml/types/qqmltableinstancemodel.cpp547
-rw-r--r--src/qml/types/qqmltableinstancemodel_p.h162
-rw-r--r--src/qml/types/qqmltablemodel.cpp1059
-rw-r--r--src/qml/types/qqmltablemodel_p.h170
-rw-r--r--src/qml/types/qqmltablemodelcolumn.cpp200
-rw-r--r--src/qml/types/qqmltablemodelcolumn_p.h224
-rw-r--r--src/qml/types/qquickpackage.cpp198
-rw-r--r--src/qml/types/qquickpackage_p.h101
-rw-r--r--src/qml/types/types.pri41
-rw-r--r--src/qml/util/qqmladaptormodel.cpp1037
-rw-r--r--src/qml/util/qqmladaptormodel_p.h179
-rw-r--r--src/qml/util/qqmlchangeset.cpp583
-rw-r--r--src/qml/util/qqmlchangeset_p.h161
-rw-r--r--src/qml/util/qqmllistaccessor.cpp160
-rw-r--r--src/qml/util/qqmllistaccessor_p.h83
-rw-r--r--src/qml/util/qqmllistcompositor.cpp1482
-rw-r--r--src/qml/util/qqmllistcompositor_p.h372
-rw-r--r--src/qml/util/util.pri14
129 files changed, 879 insertions, 27603 deletions
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index 21d653af55..346cfb5803 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -704,8 +704,9 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const CompiledObject *targetObject = objectContainer->objectAt(
- objectForId(component, lastAlias->targetObjectId));
+ const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+ const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
auto nextAlias = targetObject->aliasesBegin();
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 1d0a57c536..acd4aa62ea 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -66,8 +66,6 @@ namespace Moth {
class BytecodeGenerator {
public:
- typedef CompiledData::Function::TraceInfoCount TraceInfoCount;
-
BytecodeGenerator(int line, bool debug)
: startLine(line), debugMode(debug) {}
@@ -164,15 +162,6 @@ public:
addInstructionHelper(Moth::Instr::Type(InstrT), genericInstr);
}
- // Same as addInstruction, but also add a trace slot. Move only, because the instruction cannot
- // be reused afterwards.
- template<int InstrT>
- void addTracingInstruction(InstrData<InstrT> data)
- {
- data.traceSlot = nextTraceInfo();
- addInstruction(data);
- }
-
Q_REQUIRED_RESULT Jump jump()
{
QT_WARNING_PUSH
@@ -184,12 +173,12 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpTrue()
{
- return addTracingJumpInstruction(Instruction::JumpTrue());
+ return addJumpInstruction(Instruction::JumpTrue());
}
Q_REQUIRED_RESULT Jump jumpFalse()
{
- return addTracingJumpInstruction(Instruction::JumpFalse());
+ return addJumpInstruction(Instruction::JumpFalse());
}
Q_REQUIRED_RESULT Jump jumpNotUndefined()
@@ -209,7 +198,7 @@ QT_WARNING_POP
Instruction::CmpStrictEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
}
void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
@@ -217,7 +206,13 @@ QT_WARNING_POP
Instruction::CmpStrictNotEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
+ }
+
+ void checkException()
+ {
+ Instruction::CheckException chk;
+ addInstruction(chk);
}
void setUnwindHandler(ExceptionHandler *handler)
@@ -258,13 +253,6 @@ QT_WARNING_POP
void finalize(Compiler::Context *context);
template<int InstrT>
- Jump addTracingJumpInstruction(InstrData<InstrT> &&data)
- {
- data.traceSlot = nextTraceInfo();
- return addJumpInstruction(data);
- }
-
- template<int InstrT>
Jump addJumpInstruction(const InstrData<InstrT> &data)
{
Instr genericInstr;
@@ -275,9 +263,9 @@ QT_WARNING_POP
void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
{
if (jumpOnFalse)
- addTracingJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
+ addJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
else
- addTracingJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
+ addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
void clearLastInstruction()
@@ -285,27 +273,6 @@ QT_WARNING_POP
lastInstrType = -1;
}
- TraceInfoCount nextTraceInfo()
- {
- // If tracing is disabled, use slot 0 to unconditionally store all trace info
- if (nTraceInfos == CompiledData::Function::NoTracing())
- return TraceInfoCount(0);
- return nTraceInfos++;
- }
-
- void setTracing(bool onoff, int argumentCount)
- {
- if (onoff)
- nTraceInfos = argumentCount;
- else
- nTraceInfos = CompiledData::Function::NoTracing();
- }
-
- TraceInfoCount traceInfoCount() const
- {
- return nTraceInfos;
- }
-
void addLoopStart(const Label &start)
{
_labelInfos.push_back({ start.index });
@@ -346,8 +313,6 @@ private:
int lastInstrType = -1;
Moth::Instr lastInstr;
- TraceInfoCount nTraceInfos = TraceInfoCount(0);
-
struct LabelInfo {
int labelIndex;
};
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 88d3dbe9c5..1bf0e7147d 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -289,13 +289,13 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case UMinus: {
expr.loadInAccumulator();
Instruction::UMinus uminus = {};
- bytecodeGenerator->addTracingInstruction(uminus);
+ bytecodeGenerator->addInstruction(uminus);
return Reference::fromAccumulator(this);
}
case UPlus: {
expr.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
return Reference::fromAccumulator(this);
}
case Not: {
@@ -315,10 +315,10 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -330,7 +330,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -341,10 +341,10 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -356,7 +356,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -1139,7 +1139,7 @@ bool Codegen::visit(ArrayPattern *ast)
index.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
index.storeConsumeAccumulator();
};
@@ -1196,11 +1196,12 @@ bool Codegen::visit(ArrayPattern *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
lhsValue.loadInAccumulator();
pushAccumulator();
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
end.link();
}
@@ -1487,20 +1488,20 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Add add;
add.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(add);
+ bytecodeGenerator->addInstruction(add);
break;
}
case QSOperator::Sub: {
if (right.isConstant() && right.constant == Encode(int(1))) {
left.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
} else {
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Sub sub;
sub.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(sub);
+ bytecodeGenerator->addInstruction(sub);
}
break;
}
@@ -1517,7 +1518,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mul mul;
mul.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mul);
+ bytecodeGenerator->addInstruction(mul);
break;
}
case QSOperator::Div: {
@@ -1533,7 +1534,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mod mod;
mod.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mod);
+ bytecodeGenerator->addInstruction(mod);
break;
}
case QSOperator::BitAnd:
@@ -1902,7 +1903,7 @@ bool Codegen::visit(CallExpression *ast)
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::TailCall call;
call.func = base.stackSlot();
@@ -1931,14 +1932,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallProperty call;
call.base = base.propertyBase.stackSlot();
call.name = base.propertyNameIndex;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
@@ -1946,33 +1947,33 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.index = base.elementSubscript.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
if (base.name == QStringLiteral("eval")) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::SuperProperty) {
Reference receiver = base.baseObject();
@@ -1989,14 +1990,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.thisObject = receiver.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Q_ASSERT(base.isStackSlot());
Instruction::CallValue call;
call.name = base.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
setExprResult(Reference::fromAccumulator(this));
@@ -2732,14 +2733,14 @@ bool Codegen::visit(TemplateLiteral *ast)
Instruction::Add instr;
instr.lhs = temp2;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
} else {
expr.loadInAccumulator();
}
Instruction::Add instr;
instr.lhs = temp;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
}
auto r = Reference::fromAccumulator(this);
@@ -2997,7 +2998,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool savedFunctionEndsWithReturn = functionEndsWithReturn;
functionEndsWithReturn = endsWithReturn(_module, body);
- bytecodeGenerator->setTracing(_functionContext->canUseTracingJit(), _context->arguments.size());
// reserve the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
@@ -3084,7 +3084,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
_context->registerCountInFunction = bytecodeGenerator->registerCount();
- _context->nTraceInfos = bytecodeGenerator->traceInfoCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
@@ -3203,11 +3202,13 @@ bool Codegen::visit(DoWhileStatement *ast)
cond.link();
if (AST::cast<TrueLiteral *>(ast->expression)) {
// do {} while (true) -> just jump back to the loop body, no need to generate a condition
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(body);
} else if (AST::cast<FalseLiteral *>(ast->expression)) {
// do {} while (false) -> fall through, no need to generate a condition
} else {
TailCallBlocker blockTailCalls(this);
+ bytecodeGenerator->checkException();
condition(ast->expression, &body, &end, false);
}
@@ -3288,7 +3289,7 @@ bool Codegen::visit(ForEachStatement *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
// each iteration gets it's own context, as per spec
{
@@ -3324,6 +3325,7 @@ bool Codegen::visit(ForEachStatement *ast)
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
}
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
error:
@@ -3372,6 +3374,7 @@ bool Codegen::visit(ForStatement *ast)
bytecodeGenerator->addInstruction(clone);
}
statement(ast->expression);
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(cond);
end.link();
@@ -3654,6 +3657,8 @@ bool Codegen::visit(WhileStatement *ast)
ControlFlowLoop flow(this, &end, &cond);
bytecodeGenerator->addLoopStart(cond);
+ bytecodeGenerator->checkException();
+
if (!AST::cast<TrueLiteral *>(ast->expression)) {
TailCallBlocker blockTailCalls(this);
condition(ast->expression, &start, &end, true);
@@ -4225,7 +4230,7 @@ void Codegen::Reference::storeAccumulator() const
Instruction::StoreElement store;
store.base = elementBase;
store.index = elementSubscript.stackSlot();
- codegen->bytecodeGenerator->addTracingInstruction(store);
+ codegen->bytecodeGenerator->addInstruction(store);
} return;
case Invalid:
case Accumulator:
@@ -4315,12 +4320,12 @@ QT_WARNING_POP
if (!scope) {
Instruction::LoadLocal load;
load.index = index;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadScopedLocal load;
load.index = index;
load.scope = scope;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
tdzCheck(requiresTDZCheck);
return;
@@ -4344,16 +4349,16 @@ QT_WARNING_POP
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Member:
@@ -4362,11 +4367,11 @@ QT_WARNING_POP
if (!disable_lookups && codegen->useFastLookups) {
Instruction::GetLookup load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadProperty load;
load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Import: {
@@ -4381,7 +4386,7 @@ QT_WARNING_POP
tdzCheck(subscriptRequiresTDZCheck);
Instruction::LoadElement load;
load.base = elementBase;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} return;
case Invalid:
break;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 4cfd2d86e8..dd7ba471c3 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x22 // Add trace slot to UPlus
+#define QV4_DATA_STRUCTURE_VERSION 0x23 // Remove trace slots
class QIODevice;
class QQmlPropertyData;
@@ -296,10 +296,6 @@ struct Function
quint32_le nLabelInfos;
size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
- typedef quint16_le TraceInfoCount;
- TraceInfoCount nTraceInfos;
- static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
-
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 01c033cb2a..123d77f788 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -424,7 +424,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
Q_ASSERT(function->lineNumberOffset() == currentOffset);
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
if (!irFunction->labelInfo.empty()) {
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 52215c2ce6..d1a5fee92b 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -410,26 +410,4 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
-bool Context::canUseTracingJit() const
-{
-#if QT_CONFIG(qml_tracing)
- static bool forceTracing = !qEnvironmentVariableIsEmpty("QV4_FORCE_TRACING");
- if (forceTracing) //### we can probably remove this when tracing is turned on by default
- return true; // to be used by unittests
-
- static bool disableTracing = !qEnvironmentVariableIsEmpty("QV4_DISABLE_TRACING");
- if (disableTracing)
- return false;
-
- static QStringList onlyTrace =
- qEnvironmentVariable("QV4_ONLY_TRACE").split(QLatin1Char(','), QString::SkipEmptyParts);
- if (!onlyTrace.isEmpty())
- return onlyTrace.contains(name);
-
- return true;
-#else
- return false;
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 57ef4be36e..f56942fffa 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -162,7 +162,6 @@ struct Context {
int line = 0;
int column = 0;
int registerCountInFunction = 0;
- uint nTraceInfos = 0;
int functionIndex = -1;
int blockIndex = -1;
@@ -363,8 +362,6 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
-
- bool canUseTracingJit() const;
};
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index b019f191fa..5148154a6a 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -171,8 +171,6 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-#define TRACE_SLOT QStringLiteral(" {%1}").arg(traceSlot)
-
void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
{
MOTH_JUMP_TABLE;
@@ -241,9 +239,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index << TRACE_SLOT;
+ d << "l" << index;
else
- d << "a" << (index - nLocals) << TRACE_SLOT;
+ d << "a" << (index - nLocals);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -255,9 +253,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope << TRACE_SLOT;
+ d << "l" << index << "@" << scope;
else
- d << "a" << (index - nLocals) << "@" << scope << TRACE_SLOT;
+ d << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -280,15 +278,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name << TRACE_SLOT;
+ d << name;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
@@ -300,20 +298,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]" << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]" << TRACE_SLOT;
+ d << "acc[" << name << "]";
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")" << TRACE_SLOT;
+ d << "acc(" << index << ")";
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -343,49 +340,48 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ ;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
d << dumpRegister(base, nFormals) << "." << lookupIndex
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
@@ -528,11 +524,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
@@ -543,6 +539,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNoException)
+ MOTH_BEGIN_INSTR(CheckException)
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
@@ -593,26 +592,22 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UPlus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(Increment)
- d << TRACE_SLOT;
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- d << TRACE_SLOT;
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
@@ -668,7 +663,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
@@ -676,11 +671,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 6a8c9a9549..35a5fdfba5 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -77,20 +77,20 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg)
#define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg)
#define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index)
-#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 2, index, traceSlot)
+#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index)
#define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index)
-#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 3, scope, index, traceSlot)
+#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index)
#define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index)
#define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId)
#define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg)
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
-#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
-#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
-#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
+#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name)
+#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
-#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
-#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
+#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -100,18 +100,18 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
-#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
-#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
-#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 5, name, thisObject, argc, argv, traceSlot)
-#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 5, name, base, argc, argv, traceSlot)
-#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 5, lookupIndex, base, argc, argv, traceSlot)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 5, base, index, argc, argv, traceSlot)
-#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
-#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
-#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
+#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base)
+#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index)
+#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv)
+#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
+#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
+#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
+#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
+#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
+#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
+#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
@@ -148,10 +148,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
-#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 2, traceSlot, offset)
-#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 2, traceSlot, offset)
+#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
+#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset)
+#define INSTR_CheckException(op) INSTRUCTION(op, CheckException, 0)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -167,12 +168,12 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpIn(op) INSTRUCTION(op, CmpIn, 1, lhs)
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
-#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 1, traceSlot)
-#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 1, traceSlot)
+#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
+#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
#define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0)
-#define INSTR_Increment(op) INSTRUCTION(op, Increment, 1, traceSlot)
-#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 1, traceSlot)
-#define INSTR_Add(op) INSTRUCTION(op, Add, 2, lhs, traceSlot)
+#define INSTR_Increment(op) INSTRUCTION(op, Increment, 0)
+#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0)
+#define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs)
#define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs)
#define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs)
#define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs)
@@ -186,10 +187,10 @@ QT_BEGIN_NAMESPACE
#define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs)
#define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs)
#define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs)
-#define INSTR_Mul(op) INSTRUCTION(op, Mul, 2, lhs, traceSlot)
+#define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
-#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
-#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
+#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
+#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -241,6 +242,7 @@ QT_BEGIN_NAMESPACE
F(JumpFalse) \
F(JumpNoException) \
F(JumpNotUndefined) \
+ F(CheckException) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
diff --git a/src/qml/configure.json b/src/qml/configure.json
index c35f5be06b..2f88aef1fb 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -8,7 +8,6 @@
"commandline": {
"options": {
"qml-network": "boolean",
- "qml-tracing": "boolean",
"qml-debug": "boolean"
}
},
@@ -24,6 +23,52 @@
],
"qmake": "CONFIG += c++11"
}
+ },
+ "pointer_32bit": {
+ "label": "32bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 4, \"fail\");"
+ }
+ },
+ "pointer_64bit": {
+ "label": "64bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 8, \"fail\");"
+ }
+ },
+ "arm_thumb": {
+ "label": "THUMB mode on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "#if defined(thumb2) || defined(__thumb2__)",
+ "# define THUMB_OK",
+ "#elif (defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4",
+ "# define THUMB_OK",
+ "#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2",
+ "// clang 3.5 and later will set this if the core supports the Thumb-2 ISA.",
+ "# define THUMB_OK",
+ "#else",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
+ },
+ "arm_fp": {
+ "label": "Sufficiently recent FPU on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "// if !defined(__ARM_FP) we might be on MSVC or we might have a device",
+ "// without an FPU.",
+ "// TODO: The latter case is not supported, but the test still succeeds.",
+ "#if defined(__ARM_FP) && (__ARM_FP <= 0x04)",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
}
},
@@ -40,12 +85,26 @@
"condition": "features.network",
"output": [ "publicFeature" ]
},
- "qml-tracing": {
- "label": "QML tracing JIT support",
- "purpose": "Provides a JIT that uses trace information generated by the interpreter.",
+ "qml-jit": {
+ "label": "QML just-in-time compiler",
+ "purpose": "Provides a JIT for QML and JavaScript",
"section": "QML",
+ "condition": [
+ " (arch.i386 && tests.pointer_32bit)
+ || (arch.x86_64 && tests.pointer_64bit)
+ || (arch.arm && tests.pointer_32bit && tests.arm_fp && tests.arm_thumb
+ && (config.linux || config.ios || config.tvos || config.qnx))
+ || (arch.arm64 && tests.pointer_64bit && tests.arm_fp
+ && (config.linux || config.ios || config.tvos || config.qnx || config.integrity))"
+ ],
"output": [ "privateFeature" ],
- "autoDetect": false
+ "autoDetect": "!config.ios && !config.tvos",
+ "comment": "On arm and arm64 we need a specialization of cacheFlush() for each OS to be
+ enabeled. Therefore the config white list.
+ Also Mind that e.g. x86_32 has arch.x86_64 but 32bit pointers. Therefore
+ the checks for architecture and pointer size.
+ Finally, ios and tvos can technically use the JIT but Apple does not allow
+ it. Therefore, it's disabled by default."
},
"qml-debug": {
"label": "QML debugging and profiling support",
@@ -90,12 +149,6 @@
"section": "QML",
"output": [ "privateFeature" ]
},
- "qml-list-model": {
- "label": "QML list model",
- "purpose": "Provides the ListModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-xml-http-request": {
"label": "QML XML http request",
"purpose": "Provides support for sending XML http requests.",
@@ -119,12 +172,6 @@
"condition": "features.animation",
"output": [ "privateFeature" ]
},
- "qml-delegate-model": {
- "label": "QML delegate model",
- "purpose": "Provides the DelegateModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-worker-script": {
"label": "QML WorkerScript",
"purpose": "Enables the use of threads in QML.",
@@ -140,12 +187,10 @@
"entries": [
"qml-network",
"qml-debug",
- "qml-tracing",
+ "qml-jit",
"qml-sequence-object",
- "qml-list-model",
"qml-xml-http-request",
- "qml-locale",
- "qml-delegate-model"
+ "qml-locale"
]
}
]
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index bc0d20dba7..503ce0ebcd 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -10,34 +10,3 @@ HEADERS += \
$$PWD/qv4baselinejit_p.h \
$$PWD/qv4baselineassembler_p.h \
$$PWD/qv4assemblercommon_p.h
-
-qtConfig(qml-tracing) {
-SOURCES += \
- $$PWD/qv4ir.cpp \
- $$PWD/qv4operation.cpp \
- $$PWD/qv4node.cpp \
- $$PWD/qv4graph.cpp \
- $$PWD/qv4graphbuilder.cpp \
- $$PWD/qv4lowering.cpp \
- $$PWD/qv4tracingjit.cpp \
- $$PWD/qv4mi.cpp \
- $$PWD/qv4domtree.cpp \
- $$PWD/qv4schedulers.cpp \
- $$PWD/qv4blockscheduler.cpp \
- $$PWD/qv4loopinfo.cpp
-
-HEADERS += \
- $$PWD/qv4ir_p.h \
- $$PWD/qv4operation_p.h \
- $$PWD/qv4runtimesupport_p.h \
- $$PWD/qv4node_p.h \
- $$PWD/qv4graph_p.h \
- $$PWD/qv4graphbuilder_p.h \
- $$PWD/qv4lowering_p.h \
- $$PWD/qv4mi_p.h \
- $$PWD/qv4miblockset_p.h \
- $$PWD/qv4domtree_p.h \
- $$PWD/qv4schedulers_p.h \
- $$PWD/qv4blockscheduler_p.h \
- $$PWD/qv4loopinfo_p.h
-}
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index dd810d9d70..800ee22cd7 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -53,8 +53,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -366,5 +364,3 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index d3d7eedae2..f305213ce2 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -58,7 +58,7 @@
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
-#ifdef V4_ENABLE_JIT
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -619,6 +619,9 @@ public:
for (Jump j : catchyJumps)
j.link(this);
+ // We don't need to check for isInterrupted here because if that is set,
+ // then the first checkException() in any exception handler will find another "exception"
+ // and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
jump(ScratchRegister);
@@ -633,6 +636,8 @@ public:
void checkException()
{
+ // This actually reads 4 bytes, starting at hasException.
+ // Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
addCatchyJump(
branch32(NotEqual,
Address(EngineRegister, offsetof(EngineBase, hasException)),
@@ -735,6 +740,4 @@ private:
QT_END_NAMESPACE
-#endif // V4_ENABLE_JIT
-
#endif // QV4PLATFORMASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 238c11f478..5e34087ff5 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -55,8 +55,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -1620,5 +1618,3 @@ void BaselineAssembler::ret()
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index 3bbaefd000..5e5d9d0672 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -55,6 +55,8 @@
#include <private/qv4function_p.h>
#include <QHash>
+QT_REQUIRE_CONFIG(qml_jit);
+
QT_BEGIN_NAMESPACE
namespace QV4 {
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 80155d7b20..f4807f1917 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -42,8 +42,6 @@
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
-#ifdef V4_ENABLE_JIT
-
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
@@ -151,7 +149,7 @@ void BaselineJIT::generate_LoadImport(int index)
as->loadImport(index);
}
-void BaselineJIT::generate_LoadLocal(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadLocal(int index)
{
as->loadLocal(index);
}
@@ -162,7 +160,7 @@ void BaselineJIT::generate_StoreLocal(int index)
as->storeLocal(index);
}
-void BaselineJIT::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
{
as->loadLocal(index, scope);
}
@@ -195,7 +193,7 @@ void BaselineJIT::generate_LoadClosure(int value)
BASELINEJIT_GENERATE_RUNTIME_CALL(Closure, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(2);
@@ -204,7 +202,7 @@ void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadGlobalLookup(int index)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
@@ -213,7 +211,7 @@ void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
@@ -243,7 +241,7 @@ void BaselineJIT::generate_StoreNameStrict(int name)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameStrict, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
+void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
@@ -254,7 +252,7 @@ void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
+void BaselineJIT::generate_StoreElement(int base, int index)
{
STORE_IP();
STORE_ACC();
@@ -266,7 +264,7 @@ void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreElement, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
@@ -277,7 +275,7 @@ void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_GetLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
STORE_ACC();
@@ -355,7 +353,7 @@ void BaselineJIT::generate_Resume(int)
Q_UNREACHABLE();
}
-void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -366,7 +364,7 @@ void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSl
BASELINEJIT_GENERATE_RUNTIME_CALL(CallValue, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -378,7 +376,7 @@ void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithReceiver, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -390,7 +388,7 @@ void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -402,7 +400,7 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -414,7 +412,7 @@ void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -425,7 +423,7 @@ void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlo
BASELINEJIT_GENERATE_RUNTIME_CALL(CallName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(3);
@@ -435,7 +433,7 @@ void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*trac
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPossiblyDirectEval, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -446,8 +444,7 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -458,7 +455,7 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int
BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -777,12 +774,12 @@ void BaselineJIT::generate_Jump(int offset)
labels.insert(as->jump(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpTrue(int offset)
{
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpFalse(int offset)
{
labels.insert(as->jumpFalse(absoluteOffset(offset)));
}
@@ -797,6 +794,11 @@ void BaselineJIT::generate_JumpNotUndefined(int offset)
labels.insert(as->jumpNotUndefined(absoluteOffset(offset)));
}
+void BaselineJIT::generate_CheckException()
+{
+ as->checkException();
+}
+
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
void BaselineJIT::generate_CmpEqInt(int lhs) { as->cmpeqInt(lhs); }
@@ -831,12 +833,12 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
}
void BaselineJIT::generate_UNot() { as->unot(); }
-void BaselineJIT::generate_UPlus(int /*traceSlot*/) { as->toNumber(); }
-void BaselineJIT::generate_UMinus(int /*traceSlot*/) { as->uminus(); }
+void BaselineJIT::generate_UPlus() { as->toNumber(); }
+void BaselineJIT::generate_UMinus() { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
-void BaselineJIT::generate_Increment(int /*traceSlot*/) { as->inc(); }
-void BaselineJIT::generate_Decrement(int /*traceSlot*/) { as->dec(); }
-void BaselineJIT::generate_Add(int lhs, int /*traceSlot*/) { as->add(lhs); }
+void BaselineJIT::generate_Increment() { as->inc(); }
+void BaselineJIT::generate_Decrement() { as->dec(); }
+void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
@@ -860,10 +862,10 @@ void BaselineJIT::generate_Exp(int lhs) {
as->passJSSlotAsArg(lhs, 0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Exp, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_Mul(int lhs, int /*traceSlot*/) { as->mul(lhs); }
+void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
-void BaselineJIT::generate_Mod(int lhs, int /*traceSlot*/) { as->mod(lhs); }
-void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
+void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
+void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
@@ -913,5 +915,3 @@ void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 37ab37eac2..284faf0ff0 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -56,7 +56,7 @@
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
-//QT_REQUIRE_CONFIG(qml_jit);
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -65,7 +65,6 @@ namespace JIT {
class BaselineAssembler;
-#ifdef V4_ENABLE_JIT
class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
@@ -88,22 +87,22 @@ public:
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
+ void generate_LoadLocal(int index) override;
void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
+ void generate_LoadScopedLocal(int scope, int index) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
+ void generate_LoadName(int name) override;
+ void generate_LoadGlobalLookup(int index) override;
+ void generate_LoadQmlContextPropertyLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
+ void generate_LoadElement(int base) override;
+ void generate_StoreElement(int base, int index) override;
+ void generate_LoadProperty(int name) override;
+ void generate_GetLookup(int index) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -112,16 +111,16 @@ public:
void generate_YieldStar() override;
void generate_Resume(int) override;
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
+ void generate_CallValue(int name, int argc, int argv) override;
+ void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
+ void generate_CallProperty(int name, int base, int argc, int argv) override;
+ void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
+ void generate_CallElement(int base, int index, int argc, int argv) override;
+ void generate_CallName(int name, int argc, int argv) override;
+ void generate_CallPossiblyDirectEval(int argc, int argv) override;
+ void generate_CallGlobalLookup(int index, int argc, int argv) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
@@ -160,10 +159,11 @@ public:
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
+ void generate_JumpTrue(int offset) override;
+ void generate_JumpFalse(int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
+ void generate_CheckException() override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
@@ -179,12 +179,12 @@ public:
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
void generate_UNot() override;
- void generate_UPlus(int) override;
- void generate_UMinus(int traceSlot) override;
+ void generate_UPlus() override;
+ void generate_UMinus() override;
void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
+ void generate_Increment() override;
+ void generate_Decrement() override;
+ void generate_Add(int lhs) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
@@ -198,10 +198,10 @@ public:
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
+ void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
+ void generate_Mod(int lhs) override;
+ void generate_Sub(int lhs) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
@@ -214,7 +214,6 @@ private:
QScopedPointer<BaselineAssembler> as;
QSet<int> labels;
};
-#endif // V4_ENABLE_JIT
} // namespace JIT
} // namespace QV4
diff --git a/src/qml/jit/qv4blockscheduler.cpp b/src/qml/jit/qv4blockscheduler.cpp
deleted file mode 100644
index 3e2bfe15c5..0000000000
--- a/src/qml/jit/qv4blockscheduler.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4blockscheduler_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcBlockScheduler, "qt.v4.ir.blockscheduler")
-
-bool BlockScheduler::checkCandidate(MIBlock *candidate)
-{
- Q_ASSERT(loopInfo.loopHeaderFor(candidate) == currentGroup.group);
-
- for (MIBlock *pred : candidate->inEdges()) {
- if (pred->isDeoptBlock())
- continue;
-
- if (emitted.alreadyProcessed(pred))
- continue;
-
- if (dominatorTree.dominates(candidate->index(), pred->index())) {
- // this is a loop, where there in
- // -> candidate edge is the jump back to the top of the loop.
- continue;
- }
-
- if (pred == candidate)
- // this is a very tight loop, e.g.:
- // L1: ...
- // goto L1
- // This can happen when, for example, the basic-block merging gets rid of the empty
- // body block. In this case, we can safely schedule this block (if all other
- // incoming edges are either loop-back edges, or have been scheduled already).
- continue;
-
- return false; // an incoming edge that is not yet emitted, and is not a back-edge
- }
-
- if (loopInfo.isLoopHeader(candidate)) {
- // postpone everything, and schedule the loop first.
- postponedGroups.push(currentGroup);
- currentGroup = WorkForGroup(candidate);
- }
-
- return true;
-}
-
-MIBlock *BlockScheduler::pickNext()
-{
- while (true) {
- while (currentGroup.postponed.isEmpty()) {
- if (postponedGroups.isEmpty())
- return nullptr;
- if (currentGroup.group) // record the first and the last node of a group
- loopsStartEnd[currentGroup.group] = sequence.back();
- currentGroup = postponedGroups.pop();
- }
-
- MIBlock *next = currentGroup.postponed.pop();
- if (checkCandidate(next))
- return next;
- }
-
- Q_UNREACHABLE();
- return nullptr;
-}
-
-void BlockScheduler::emitBlock(MIBlock *bb)
-{
- if (emitted.alreadyProcessed(bb))
- return;
-
- sequence.push_back(bb);
- emitted.markAsProcessed(bb);
-}
-
-void BlockScheduler::schedule(MIBlock *functionEntryPoint)
-{
- MIBlock *next = functionEntryPoint;
-
- while (next) {
- emitBlock(next);
- // postpone all outgoing edges, if they were not already processed
- QVarLengthArray<MIBlock *, 32> nonExceptionEdges;
- // first postpone all exception edges, so they will be processed last
- for (int i = next->outEdges().size(); i != 0; ) {
- --i;
- MIBlock *out = next->outEdges().at(i);
- if (emitted.alreadyProcessed(out))
- continue;
- if (out == nullptr)
- continue;
- if (out->instructions().front().opcode() == Meta::OnException)
- postpone(out);
- else
- nonExceptionEdges.append(out);
- }
- for (MIBlock *edge : nonExceptionEdges)
- postpone(edge);
- next = pickNext();
- }
-
- // finally schedule all de-optimization blocks at the end
- for (auto bb : dominatorTree.function()->blocks()) {
- if (bb->isDeoptBlock())
- emitBlock(bb);
- }
-}
-
-void BlockScheduler::postpone(MIBlock *bb)
-{
- if (currentGroup.group == loopInfo.loopHeaderFor(bb)) {
- currentGroup.postponed.append(bb);
- return;
- }
-
- for (int i = postponedGroups.size(); i != 0; ) {
- --i;
- WorkForGroup &g = postponedGroups[i];
- if (g.group == loopInfo.loopHeaderFor(bb)) {
- g.postponed.append(bb);
- return;
- }
- }
-
- Q_UNREACHABLE();
-}
-
-void BlockScheduler::dump() const
-{
- if (!lcBlockScheduler().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Scheduled blocks:\n");
- for (auto *bb : sequence) {
- s += QLatin1String(" L") + QString::number(bb->index());
- MIBlock *loopEnd = loopsStartEnd[bb];
- if (loopEnd)
- s += QLatin1String(", loop start, ends at L") + QString::number(loopEnd->index());
- s += QLatin1Char('\n');
- }
- qCDebug(lcBlockScheduler).noquote().nospace() << s;
-}
-
-BlockScheduler::BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo)
- : dominatorTree(dominatorTree)
- , loopInfo(loopInfo)
- , sequence(0)
- , emitted(dominatorTree.function())
-{
- schedule(dominatorTree.function()->blocks().front());
-
- dump();
-
- if (dominatorTree.function()->blockCount() != sequence.size()) {
- qFatal("The block scheduler did not schedule all blocks. This is most likely due to"
- "a non-natural loop.");
- // Usually caused by having an execution path that manages to skip over unwind handler
- // reset: any exception happening after will jump back to the unwind handler, and thereby
- // creating a loop that can be entered in 2 different ways.
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4blockscheduler_p.h b/src/qml/jit/qv4blockscheduler_p.h
deleted file mode 100644
index 1289fda9f0..0000000000
--- a/src/qml/jit/qv4blockscheduler_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4BLOCKSCHEDULER_P_H
-#define QV4BLOCKSCHEDULER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qstack.h>
-
-#include "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-class LoopInfo;
-
-// High-level algorithm:
-// 0. start with the first node (the start node) of a function
-// 1. emit the node
-// 2. add all outgoing edges that are not yet emitted to the postponed stack
-// 3. When the postponed stack is empty, pop a stack from the loop stack. If that is empty too,
-// we're done.
-// 4. pop a node from the postponed stack, and check if it can be scheduled:
-// a. if all incoming edges are scheduled, go to 4.
-// b. if an incoming edge is unscheduled, but it's a back-edge (an edge in a loop that jumps
-// back to the start of the loop), ignore it
-// c. if there is any unscheduled edge that is not a back-edge, ignore this node, and go to 4.
-// 5. if this node is the start of a loop, push the postponed stack on the loop stack.
-// 6. go back to 1.
-//
-// The postponing action in step 2 will put the node into its containing group. The case where this
-// is important is when a (labeled) continue or a (labeled) break statement occur in a loop: the
-// outgoing edge points to a node that is not part of the current loop (and possibly not of the
-// parent loop).
-//
-// Linear scan register allocation benefits greatly from short life-time intervals with few holes
-// (see for example section 4 (Lifetime Analysis) of [Wimmer1]). This algorithm makes sure that the
-// blocks of a group are scheduled together, with no non-loop blocks in between. This applies
-// recursively for nested loops. It also schedules groups of if-then-else-endif blocks together for
-// the same reason.
-class BlockScheduler
-{
- const DominatorTree &dominatorTree;
- const LoopInfo &loopInfo;
-
- struct WorkForGroup
- {
- MIBlock *group;
- QStack<MIBlock *> postponed;
-
- WorkForGroup(MIBlock *group = nullptr) : group(group) {}
- };
- WorkForGroup currentGroup;
- QStack<WorkForGroup> postponedGroups;
- std::vector<MIBlock *> sequence;
-
- class ProcessedBlocks
- {
- BitVector processed;
-
- public:
- ProcessedBlocks(MIFunction *function)
- : processed(int(function->blockCount()), false)
- {}
-
- bool alreadyProcessed(MIBlock *bb) const
- {
- Q_ASSERT(bb);
-
- return processed.at(bb->index());
- }
-
- void markAsProcessed(MIBlock *bb)
- {
- processed.setBit(bb->index());
- }
- } emitted;
- QHash<MIBlock *, MIBlock *> loopsStartEnd;
-
- bool checkCandidate(MIBlock *candidate);
- MIBlock *pickNext();
- void emitBlock(MIBlock *bb);
- void schedule(MIBlock *functionEntryPoint);
- void postpone(MIBlock *bb);
- void dump() const;
-
-public:
- BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo);
-
- const std::vector<MIBlock *> &scheduledBlockSequence() const
- { return sequence; }
-
- QHash<MIBlock *, MIBlock *> loopEndsByStartBlock() const
- { return loopsStartEnd; }
-};
-
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4BLOCKSCHEDULER_P_H
diff --git a/src/qml/jit/qv4domtree.cpp b/src/qml/jit/qv4domtree.cpp
deleted file mode 100644
index 9484f4e2dc..0000000000
--- a/src/qml/jit/qv4domtree.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qbuffer.h>
-
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcDomTree, "qt.v4.ir.domTree")
-Q_LOGGING_CATEGORY(lcDomFrontier, "qt.v4.ir.domFrontier")
-
-DominatorTree::DominatorTree(MIFunction *f)
- : m_function(f)
- , m_data(new Data)
-{
- calculateIDoms();
- m_data.reset();
-}
-
-void DominatorTree::dumpImmediateDominators() const
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Immediate dominators for " << m_function->irFunction()->name() << ":" << endl;
- for (MIBlock *to : m_function->blocks()) {
- MIBlock::Index from = m_idom.at(to->index());
- if (from != MIBlock::InvalidIndex)
- qout << " " << from;
- else
- qout << " (none)";
- qout << " dominates " << to->index() << endl;
- }
- qCDebug(lcDomTree, "%s", buf.data().constData());
-}
-
-void DominatorTree::setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator)
-{
- if (m_idom.size() <= size_t(dominated))
- m_idom.resize(dominated + 1);
- m_idom[dominated] = dominator;
-}
-
-bool DominatorTree::dominates(MIBlock::Index dominator, MIBlock::Index dominated) const
-{
- // dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
- Q_ASSERT(dominated != MIBlock::InvalidIndex);
-
- if (dominator == dominated)
- return false;
-
- for (MIBlock::Index it = m_idom[dominated]; it != MIBlock::InvalidIndex; it = m_idom[it]) {
- if (it == dominator)
- return true;
- }
-
- return false;
-}
-
-// Calculate a depth-first iteration order on the nodes of the dominator tree.
-//
-// The order of the nodes in the vector is not the same as one where a recursive depth-first
-// iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth.
-// So for the:
-// 1 dominates 2
-// 2 dominates 3
-// 3 dominates 4
-// 2 dominates 5
-// the order will be:
-// 4, 3, 5, 2, 1
-// or:
-// 4, 5, 3, 2, 1
-// So the order of nodes on the same depth is undefined, but it will be after the nodes
-// they dominate, and before the nodes that dominate them.
-//
-// The reason for this order is that a proper DFS pre-/post-order would require inverting
-// the idom vector by either building a real tree datastructure or by searching the idoms
-// for siblings and children. Both have a higher time complexity than sorting by depth.
-std::vector<MIBlock *> DominatorTree::calculateDFNodeIterOrder() const
-{
- std::vector<int> depths = calculateNodeDepths();
- std::vector<MIBlock *> order = m_function->blocks();
- std::sort(order.begin(), order.end(), [&depths](MIBlock *one, MIBlock *two) -> bool {
- return depths.at(one->index()) > depths.at(two->index());
- });
- return order;
-}
-
-// Algorithm:
-// - for each node:
-// - get the depth of a node. If it's unknown (-1):
-// - get the depth of the immediate dominator.
-// - if that's unknown too, calculate it by calling calculateNodeDepth
-// - set the current node's depth to that of immediate dominator + 1
-std::vector<int> DominatorTree::calculateNodeDepths() const
-{
- std::vector<int> nodeDepths(size_t(m_function->blockCount()), -1);
- for (MIBlock *bb : m_function->blocks()) {
- int &bbDepth = nodeDepths[bb->index()];
- if (bbDepth == -1) {
- const int immDom = m_idom[bb->index()];
- if (immDom == -1) {
- // no immediate dominator, so it's either the start block, or an unreachable block
- bbDepth = 0;
- } else {
- int immDomDepth = nodeDepths[immDom];
- if (immDomDepth == -1)
- immDomDepth = calculateNodeDepth(immDom, nodeDepths);
- bbDepth = immDomDepth + 1;
- }
- }
- }
- return nodeDepths;
-}
-
-// Algorithm:
-// - search for the first dominator of a node that has a known depth. As all nodes are
-// reachable from the start node, and that node's depth is 0, this is finite.
-// - while doing that search, put all unknown nodes in the worklist
-// - pop all nodes from the worklist, and set their depth to the previous' (== dominating)
-// node's depth + 1
-// This way every node's depth is calculated once, and the complexity is O(n).
-int DominatorTree::calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const
-{
- std::vector<int> worklist;
- worklist.reserve(8);
- int depth = -1;
-
- do {
- worklist.push_back(nodeIdx);
- nodeIdx = m_idom[nodeIdx];
- depth = nodeDepths[nodeIdx];
- } while (depth == -1);
-
- for (auto it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it)
- nodeDepths[*it] = ++depth;
-
- return depth;
-}
-
-namespace {
-struct DFSTodo {
- MIBlock::Index node = MIBlock::InvalidIndex;
- MIBlock::Index parent = MIBlock::InvalidIndex;
-
- DFSTodo() = default;
- DFSTodo(MIBlock::Index node, MIBlock::Index parent)
- : node(node)
- , parent(parent)
- {}
-};
-} // anonymous namespace
-
-void DominatorTree::dfs(MIBlock::Index node)
-{
- std::vector<DFSTodo> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
- DFSTodo todo(node, MIBlock::InvalidIndex);
-
- while (true) {
- MIBlock::Index n = todo.node;
-
- if (m_data->dfnum[n] == 0) {
- m_data->dfnum[n] = m_data->size;
- m_data->vertex[m_data->size] = n;
- m_data->parent[n] = todo.parent;
- ++m_data->size;
-
- MIBlock::OutEdges out = m_function->block(n)->outEdges();
- for (int i = out.size() - 1; i > 0; --i)
- worklist.emplace_back(out[i]->index(), n);
-
- if (!out.isEmpty()) {
- todo.node = out.first()->index();
- todo.parent = n;
- continue;
- }
- }
-
- if (worklist.empty())
- break;
-
- todo = worklist.back();
- worklist.pop_back();
- }
-}
-
-void DominatorTree::link(MIBlock::Index p, MIBlock::Index n)
-{
- m_data->ancestor[n] = p;
- m_data->best[n] = n;
-}
-
-void DominatorTree::calculateIDoms()
-{
- Q_ASSERT(m_function->block(0)->inEdges().count() == 0);
-
- const size_t bbCount = m_function->blockCount();
- m_data->vertex = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->parent = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->dfnum = std::vector<unsigned>(bbCount, 0);
- m_data->semi = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->ancestor = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_idom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->samedom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->best = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
-
- QHash<MIBlock::Index, std::vector<MIBlock::Index>> bucket;
- bucket.reserve(int(bbCount));
-
- dfs(m_function->block(0)->index());
-
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
-
- for (int i = m_data->size - 1; i > 0; --i) {
- MIBlock::Index n = m_data->vertex[i];
- MIBlock::Index p = m_data->parent[n];
- MIBlock::Index s = p;
-
- for (auto inEdge : m_function->block(n)->inEdges()) {
- if (inEdge->isDeoptBlock())
- continue;
- MIBlock::Index v = inEdge->index();
- MIBlock::Index ss = MIBlock::InvalidIndex;
- if (m_data->dfnum[v] <= m_data->dfnum[n])
- ss = v;
- else
- ss = m_data->semi[ancestorWithLowestSemi(v, worklist)];
- if (m_data->dfnum[ss] < m_data->dfnum[s])
- s = ss;
- }
- m_data->semi[n] = s;
- bucket[s].push_back(n);
- link(p, n);
- if (bucket.contains(p)) {
- for (MIBlock::Index v : bucket[p]) {
- MIBlock::Index y = ancestorWithLowestSemi(v, worklist);
- MIBlock::Index semi_v = m_data->semi[v];
- if (m_data->semi[y] == semi_v)
- m_idom[v] = semi_v;
- else
- m_data->samedom[v] = y;
- }
- bucket.remove(p);
- }
- }
-
- for (unsigned i = 1; i < m_data->size; ++i) {
- MIBlock::Index n = m_data->vertex[i];
- Q_ASSERT(n != MIBlock::InvalidIndex);
- Q_ASSERT(!bucket.contains(n));
- Q_ASSERT(m_data->ancestor[n] != MIBlock::InvalidIndex);
- Q_ASSERT((m_data->semi[n] != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->ancestor[n]] <= m_data->dfnum[m_data->semi[n]])
- || m_data->semi[n] == n);
- MIBlock::Index sdn = m_data->samedom[n];
- if (sdn != MIBlock::InvalidIndex)
- m_idom[n] = m_idom[sdn];
- }
-
- if (lcDomTree().isDebugEnabled())
- dumpImmediateDominators();
-
- m_data.reset(nullptr);
-}
-
-MIBlock::Index DominatorTree::ancestorWithLowestSemi(MIBlock::Index v,
- std::vector<MIBlock::Index> &worklist)
-{
- worklist.clear();
- for (MIBlock::Index it = v; it != MIBlock::InvalidIndex; it = m_data->ancestor[it])
- worklist.push_back(it);
-
- if (worklist.size() < 2)
- return m_data->best[v];
-
- MIBlock::Index b = MIBlock::InvalidIndex;
- MIBlock::Index last = worklist.back();
- Q_ASSERT(worklist.size() <= INT_MAX);
- for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) {
- MIBlock::Index bbIt = worklist[it];
- m_data->ancestor[bbIt] = last;
- MIBlock::Index &best_it = m_data->best[bbIt];
- if (b != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->semi[b]] < m_data->dfnum[m_data->semi[best_it]]) {
- best_it = b;
- } else {
- b = best_it;
- }
- }
- return b;
-}
-
-void DominatorFrontier::compute(const DominatorTree &domTree)
-{
- struct NodeProgress {
- std::vector<MIBlock::Index> children;
- std::vector<MIBlock::Index> todo;
- };
-
- MIFunction *function = domTree.function();
- m_df.resize(function->blockCount());
-
- // compute children of each node in the dominator tree
- std::vector<std::vector<MIBlock::Index> > children; // BasicBlock index -> children
- children.resize(function->blockCount());
- for (MIBlock *n : function->blocks()) {
- const MIBlock::Index nodeIndex = n->index();
- Q_ASSERT(function->block(nodeIndex) == n);
- const MIBlock::Index nodeDominator = domTree.immediateDominator(nodeIndex);
- if (nodeDominator == MIBlock::InvalidIndex)
- continue; // there is no dominator to add this node to as a child (e.g. the start node)
- children[nodeDominator].push_back(nodeIndex);
- }
-
- // Fill the worklist and initialize the node status for each basic-block
- std::vector<NodeProgress> nodeStatus;
- nodeStatus.resize(function->blockCount());
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(function->blockCount());
- for (MIBlock *bb : function->blocks()) {
- MIBlock::Index nodeIndex = bb->index();
- worklist.push_back(nodeIndex);
- NodeProgress &np = nodeStatus[nodeIndex];
- np.children = children[nodeIndex];
- np.todo = children[nodeIndex];
- }
-
- BitVector DF_done(int(function->blockCount()), false);
-
- while (!worklist.empty()) {
- MIBlock::Index node = worklist.back();
-
- if (DF_done.at(node)) {
- worklist.pop_back();
- continue;
- }
-
- NodeProgress &np = nodeStatus[node];
- auto it = np.todo.begin();
- while (it != np.todo.end()) {
- if (DF_done.at(*it)) {
- it = np.todo.erase(it);
- } else {
- worklist.push_back(*it);
- break;
- }
- }
-
- if (np.todo.empty()) {
- MIBlockSet &miBlockSet = m_df[node];
- miBlockSet.init(function);
- for (MIBlock *y : function->block(node)->outEdges()) {
- if (domTree.immediateDominator(y->index()) != node)
- miBlockSet.insert(y);
- }
- for (MIBlock::Index child : np.children) {
- const MIBlockSet &ws = m_df[child];
- for (auto w : ws) {
- const MIBlock::Index wIndex = w->index();
- if (node == wIndex || !domTree.dominates(node, w->index()))
- miBlockSet.insert(w);
- }
- }
- DF_done.setBit(node);
- worklist.pop_back();
- }
- }
-
- if (lcDomFrontier().isDebugEnabled())
- dump(domTree.function());
-}
-
-void DominatorFrontier::dump(MIFunction *function)
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Dominator Frontiers:" << endl;
- for (MIBlock *n : function->blocks()) {
- qout << "\tDF[" << n->index() << "]: {";
- const MIBlockSet &SList = m_df[n->index()];
- for (MIBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) {
- if (i != SList.begin())
- qout << ", ";
- qout << (*i)->index();
- }
- qout << "}" << endl;
- }
- qCDebug(lcDomFrontier, "%s", buf.data().constData());
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4domtree_p.h b/src/qml/jit/qv4domtree_p.h
deleted file mode 100644
index 703e17ab61..0000000000
--- a/src/qml/jit/qv4domtree_p.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4DOMTREE_P_H
-#define QV4DOMTREE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-#include "qv4miblockset_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree
-{
- Q_DISABLE_COPY_MOVE(DominatorTree)
-
-public:
- DominatorTree(MIFunction *f);
- ~DominatorTree() = default;
-
- void dumpImmediateDominators() const;
- MIFunction *function() const
- { return m_function; }
-
- void setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator);
-
- MIBlock::Index immediateDominator(MIBlock::Index blockIndex) const
- { return m_idom[blockIndex]; }
-
- bool dominates(MIBlock::Index dominator, MIBlock::Index dominated) const;
-
- bool insideSameDominatorChain(MIBlock::Index one, MIBlock::Index other) const
- { return one == other || dominates(one, other) || dominates(other, one); }
-
- std::vector<MIBlock *> calculateDFNodeIterOrder() const;
-
- std::vector<int> calculateNodeDepths() const;
-
-private: // functions
- int calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const;
- void link(MIBlock::Index p, MIBlock::Index n);
- void calculateIDoms();
- void dfs(MIBlock::Index node);
- MIBlock::Index ancestorWithLowestSemi(MIBlock::Index v, std::vector<MIBlock::Index> &worklist);
-
-private: // data
- struct Data {
- std::vector<unsigned> dfnum; // MIBlock index -> dfnum
- std::vector<MIBlock::Index> vertex;
- std::vector<MIBlock::Index> parent; // MIBlock index -> parent MIBlock index
- std::vector<MIBlock::Index> ancestor; // MIBlock index -> ancestor MIBlock index
- std::vector<MIBlock::Index> best; // MIBlock index -> best MIBlock index
- std::vector<MIBlock::Index> semi; // MIBlock index -> semi dominator MIBlock index
- std::vector<MIBlock::Index> samedom; // MIBlock index -> same dominator MIBlock index
- unsigned size = 0;
- };
-
- MIFunction *m_function;
- QScopedPointer<Data> m_data;
- std::vector<MIBlock::Index> m_idom; // MIBlock index -> immediate dominator MIBlock index
-};
-
-class DominatorFrontier
-{
-public:
- DominatorFrontier(const DominatorTree &domTree)
- { compute(domTree); }
-
- const MIBlockSet &operator[](MIBlock *n) const
- { return m_df[n->index()]; }
-
-private: // functions
- void compute(const DominatorTree &domTree);
- void dump(MIFunction *function);
-
-private: // data
- std::vector<MIBlockSet> m_df; // MIBlock index -> dominator frontier
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4DOMTREE_P_H
diff --git a/src/qml/jit/qv4graph.cpp b/src/qml/jit/qv4graph.cpp
deleted file mode 100644
index 4025ceb993..0000000000
--- a/src/qml/jit/qv4graph.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4graph_p.h"
-#include "qv4operation_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Graph *Graph::create(Function *function)
-{
- auto storage = function->pool()->allocate(sizeof(Graph));
- auto g = new (storage) Graph(function);
- g->m_undefinedNode = g->createNode(g->opBuilder()->get<Meta::Undefined>());
- g->m_emptyNode = g->createNode(g->opBuilder()->get<Meta::Empty>());
- g->m_nullNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::nullValue()));
- g->m_trueNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(true)));
- g->m_falseNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(false)));
- return g;
-}
-
-Graph::MemoryPool *Graph::pool() const
-{
- return m_function->pool();
-}
-
-Node *Graph::createNode(const Operation *op, Node *const operands[], size_t opCount,
- bool incomplete)
-{
- return Node::create(pool(), m_nextNodeId++, op, opCount, operands, incomplete);
-}
-
-Node *Graph::createConstantBoolNode(bool value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromBoolean(value)));
-}
-
-Node *Graph::createConstantIntNode(int value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromInt32(value)));
-}
-
-Graph::Graph(Function *function)
- : m_function(function)
- , m_opBuilder(OperationBuilder::create(pool()))
-{}
-
-Node *Graph::createConstantHeapNode(Heap::Base *heap)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromHeapObject(heap)));
-}
-
-void Graph::addEndInput(Node *n)
-{
- if (m_endNode) {
- auto newEnd = m_opBuilder->getEnd(m_endNode->operation()->controlInputCount() + 1);
- m_endNode->setOperation(newEnd);
- m_endNode->addInput(m_function->pool(), n);
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graph_p.h b/src/qml/jit/qv4graph_p.h
deleted file mode 100644
index 4706399c94..0000000000
--- a/src/qml/jit/qv4graph_p.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPH_P_H
-#define QV4GRAPH_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4node_p.h>
-
-#include <array>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Function;
-class Operation;
-class OperationBuilder;
-
-class Graph final
-{
- Q_DISABLE_COPY_MOVE(Graph)
-
-public:
- using MemoryPool = QQmlJS::MemoryPool;
-
-public:
- static Graph *create(Function *function);
- ~Graph() = delete;
-
- MemoryPool *pool() const;
- OperationBuilder *opBuilder() const
- { return m_opBuilder; }
-
- Node *createNode(const Operation *op, Node * const operands[] = nullptr, size_t opCount = 0,
- bool incomplete = false);
- template <typename... Nodes>
- Node *createNode(Operation *op, Nodes*... nodes) {
- std::array<Node *, sizeof...(nodes)> nodesArray {{ nodes... }};
- return createNode(op, nodesArray.data(), nodesArray.size());
- }
- Node *createConstantBoolNode(bool value);
- Node *createConstantIntNode(int value);
- Node *createConstantHeapNode(Heap::Base *heap);
-
- Node *undefinedNode() const { return m_undefinedNode; }
- Node *emptyNode() const { return m_emptyNode; }
- Node *nullNode() const { return m_nullNode; }
- Node *trueConstant() const { return m_trueNode; }
- Node *falseConstant() const { return m_falseNode; }
-
- Node *startNode() const { return m_startNode; }
- Node *engineNode() const { return m_engineNode; }
- Node *functionNode() const { return m_functionNode; }
- Node *cppFrameNode() const { return m_cppFrameNode; }
- Node *endNode() const { return m_endNode; }
- Node *initialFrameState() const { return m_initialFrameState; }
- void setStartNode(Node *n) { m_startNode = n; }
- void setEngineNode(Node *n) { m_engineNode = n; }
- void setFunctionNode(Node *n) { m_functionNode = n; }
- void setCppFrameNode(Node *n) { m_cppFrameNode = n; }
- void setEndNode(Node *n) { m_endNode = n; }
- void setInitialFrameState(Node *n) { m_initialFrameState = n; }
-
- unsigned nodeCount() const
- { return unsigned(m_nextNodeId); }
-
- void addEndInput(Node *n);
-
-private: // types and methods
- Graph(Function *function);
-
-private: // fields
- Function *m_function;
- OperationBuilder *m_opBuilder;
- Node::Id m_nextNodeId = 0;
- Node *m_undefinedNode = nullptr;
- Node *m_emptyNode = nullptr;
- Node *m_nullNode = nullptr;
- Node *m_trueNode = nullptr;
- Node *m_falseNode = nullptr;
- Node *m_startNode = nullptr;
- Node *m_engineNode = nullptr;
- Node *m_functionNode = nullptr;
- Node *m_cppFrameNode = nullptr;
- Node *m_endNode = nullptr;
- Node *m_initialFrameState = nullptr;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPH_P_H
diff --git a/src/qml/jit/qv4graphbuilder.cpp b/src/qml/jit/qv4graphbuilder.cpp
deleted file mode 100644
index 2c073701ee..0000000000
--- a/src/qml/jit/qv4graphbuilder.cpp
+++ /dev/null
@@ -1,1683 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4graphbuilder_p.h"
-#include "qv4function_p.h"
-#include "qv4lookup_p.h"
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcIRGraphBuilder, "qt.v4.ir.graphbuilder")
-
-using MemoryPool = QQmlJS::MemoryPool;
-
-namespace {
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-
-template <typename Array>
-inline size_t arraySize(const Array &array)
-{
- Q_UNUSED(array); // for MSVC
- return sizeof(ArraySizeHelper(array));
-}
-} // anonymous namespace
-
-class GraphBuilder::InterpreterEnvironment
-{
-public:
- struct FrameState: public QQmlJS::FixedPoolArray<Node *>
- {
- FrameState(MemoryPool *pool, int totalSlotCount)
- : FixedPoolArray(pool, totalSlotCount)
- {}
-
- Node *&unwindHandlerOffset()
- { return at(size() - 1); }
-
- static FrameState *create(MemoryPool *pool, int jsSlotCount)
- {
- auto totalSlotCount = jsSlotCount;
- auto fs = pool->New<FrameState>(pool, totalSlotCount);
- return fs;
- }
-
- static FrameState *clone(MemoryPool *pool, FrameState *other)
- {
- FrameState *fs = create(pool, other->size());
-
- for (int i = 0, ei = other->size(); i != ei; ++i)
- fs->at(i) = other->at(i);
-
- return fs;
- }
- };
-
-public:
- InterpreterEnvironment(GraphBuilder *graphBuilder, Node *controlDependency)
- : m_graphBuilder(graphBuilder)
- , m_effectDependency(controlDependency)
- , m_controlDependency(controlDependency)
- , m_currentFrame(nullptr)
- {}
-
- void createEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- // 1 extra slot for the unwindHandlerOffset
- m_currentFrame = FrameState::create(graph()->pool(), int(nRegisters + 1));
- }
-
- void setupStartEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nFormals = v4Function->compiledFunction->nFormals;
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- createEnvironment();
-
- Node *startNode = graph()->startNode();
- auto opB = opBuilder();
- auto create = [&](int index, const char *name) {
- m_currentFrame->at(index) = graph()->createNode(
- opB->getParam(index, f->addString(QLatin1String(name))), startNode);
- };
- create(0, "%function");
- create(1, "%context");
- create(2, "%acc");
- create(3, "%this");
- create(4, "%newTarget");
- create(5, "%argc");
- const quint32_le *formalNameIdx = v4Function->compiledFunction->formalsTable();
- for (size_t i = 0; i < nFormals; ++i, ++formalNameIdx) {
- const int slot = int(CallData::HeaderSize() + i);
- Q_ASSERT(*formalNameIdx <= quint32(std::numeric_limits<int>::max()));
- auto op = opB->getParam(
- slot,
- f->addString(v4Function->compilationUnit->stringAt(int(*formalNameIdx))));
- Node *argNode = graph()->createNode(op, startNode);
- m_currentFrame->at(slot) = argNode;
- }
- Node *undefinedNode = graph()->undefinedNode();
- Node *emptyNode = graph()->emptyNode();
- const auto firstDeadZoneRegister
- = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
- const auto registerDeadZoneSize
- = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
- for (size_t i = CallData::HeaderSize() + nFormals; i < nRegisters; ++i) {
- const bool isDead = i >= firstDeadZoneRegister
- && i < size_t(firstDeadZoneRegister + registerDeadZoneSize);
- m_currentFrame->at(int(i)) = isDead ? emptyNode : undefinedNode;
- }
- setUnwindHandlerOffset(0);
- }
-
- Function *function() const { return m_graphBuilder->function(); }
- Graph *graph() const { return function()->graph(); }
- OperationBuilder *opBuilder() const { return graph()->opBuilder(); }
- GraphBuilder *graphBuilder() const { return m_graphBuilder; }
-
- Node *bindAcc(Node *node)
- {
- bindNodeToSlot(node, CallData::Accumulator);
- return node;
- }
-
- Node *accumulator() const
- { return slot(CallData::Accumulator); }
-
- Node *bindNodeToSlot(Node *node, int slot)
- {
- m_currentFrame->at(size_t(slot)) = node;
- return node;
- }
-
- Node *slot(int slot) const
- { return m_currentFrame->at(slot); }
-
- int slotCount() const
- { return m_currentFrame->size(); }
-
- Node *effectDependency() const
- { return m_effectDependency; }
-
- void setEffectDependency(Node *newNode)
- { m_effectDependency = newNode; }
-
- Node *controlDependency() const
- { return m_controlDependency; }
-
- void setControlDependency(Node *newNode)
- { m_controlDependency = newNode; }
-
- Node *createFrameState()
- {
- return graph()->createNode(graphBuilder()->opBuilder()->getFrameState(slotCount()),
- m_currentFrame->begin(), slotCount());
- }
-
- Node *merge(InterpreterEnvironment *other);
-
- InterpreterEnvironment *copy() const
- {
- auto *newEnv = graph()->pool()->New<InterpreterEnvironment>(graphBuilder(),
- controlDependency());
- newEnv->setEffectDependency(effectDependency());
- newEnv->m_currentFrame = FrameState::clone(graph()->pool(), m_currentFrame);
- return newEnv;
- }
-
- int unwindHandlerOffset() const
- {
- auto uhOp = m_currentFrame->unwindHandlerOffset()->operation();
- Q_ASSERT(uhOp->kind() == Meta::Constant);
- return ConstantPayload::get(*uhOp)->value().int_32();
- }
-
- void setUnwindHandlerOffset(int newOffset)
- { m_currentFrame->unwindHandlerOffset() = graphBuilder()->createConstant(newOffset); }
-
- FrameState *frameState() const
- { return m_currentFrame; }
-
-private:
- GraphBuilder *m_graphBuilder;
- Node *m_effectDependency;
- Node *m_controlDependency;
- FrameState *m_currentFrame;
-};
-
-namespace {
-class InterpreterSubEnvironment final
-{
- Q_DISABLE_COPY_MOVE(InterpreterSubEnvironment)
-
-public:
- explicit InterpreterSubEnvironment(GraphBuilder *builder)
- : m_builder(builder)
- , m_parent(builder->env()->copy())
- {}
-
- ~InterpreterSubEnvironment()
- { m_builder->setEnv(m_parent); }
-
-private:
- GraphBuilder *m_builder;
- GraphBuilder::InterpreterEnvironment *m_parent;
-};
-} // anonymous namespace
-
-Node *GraphBuilder::InterpreterEnvironment::merge(InterpreterEnvironment *other)
-{
- Q_ASSERT(m_currentFrame->size() == other->m_currentFrame->size());
-
- auto gb = graphBuilder();
- Node *mergedControl = gb->mergeControl(controlDependency(), other->controlDependency());
- setControlDependency(mergedControl);
- setEffectDependency(gb->mergeEffect(effectDependency(), other->effectDependency(), mergedControl));
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = m_currentFrame->size() - 1; i != ei; ++i) {
- //### use lifeness info to trim this!
- m_currentFrame->at(i) = gb->mergeValue(m_currentFrame->at(i),
- other->m_currentFrame->at(i),
- mergedControl);
- }
- Q_ASSERT(unwindHandlerOffset() >= 0); // specifically: don't crash
- return mergedControl;
-}
-
-void GraphBuilder::buildGraph(IR::Function *function)
-{
- const char *code = function->v4Function()->codeData;
- uint len = function->v4Function()->compiledFunction->codeSize;
-
- GraphBuilder builder(function);
- builder.startGraph();
-
- InterpreterEnvironment initial(&builder, function->graph()->startNode());
- initial.setupStartEnvironment();
- builder.setEnv(&initial);
- builder.graph()->setInitialFrameState(initial.createFrameState());
- builder.decode(code, len);
- builder.endGraph();
-};
-
-GraphBuilder::GraphBuilder(IR::Function *function)
- : m_func(function)
- , m_graph(function->graph())
- , m_currentEnv(nullptr)
-{
- for (unsigned i = 0, ei = m_func->v4Function()->compiledFunction->nLabelInfos; i != ei; ++i) {
- unsigned label = m_func->v4Function()->compiledFunction->labelInfoTable()[i];
- m_labelInfos.emplace_back(label);
- if (lcIRGraphBuilder().isDebugEnabled()) {
- const LabelInfo &li = m_labelInfos.back();
- qCDebug(lcIRGraphBuilder) << "Loop start at" << li.labelOffset;
- }
- }
-}
-
-void GraphBuilder::startGraph()
-{
- size_t nValuesOut = 1 + CallData::HeaderSize()
- + m_func->v4Function()->compiledFunction->nFormals;
- Node *start = m_graph->createNode(opBuilder()->getStart(uint16_t(nValuesOut)), nullptr, 0);
- m_func->nodeInfo(start)->setBytecodeOffsets(0, 0);
- m_graph->setStartNode(start);
- m_graph->setEngineNode(m_graph->createNode(opBuilder()->get<Meta::Engine>(), &start, 1));
- auto frame = m_graph->createNode(opBuilder()->get<Meta::CppFrame>(), &start, 1);
- m_graph->setCppFrameNode(frame);
- m_graph->setFunctionNode(m_graph->createNode(opBuilder()->get<Meta::Function>(),
- &frame, 1));
-}
-
-void GraphBuilder::endGraph()
-{
- const auto inputCount = uint16_t(m_exitControls.size());
- Node **inputs = &m_exitControls.front();
- Q_ASSERT(m_graph->endNode() == nullptr);
- m_graph->setEndNode(m_graph->createNode(opBuilder()->getEnd(inputCount), inputs, inputCount));
-}
-
-Node *GraphBuilder::bindAcc(Node *n)
-{
- return env()->bindAcc(n);
-}
-
-/* IMPORTANT!!!
- *
- * This might change the success environment, so don't call:
- * env()->bindAcc(createNode(...))
- * because the binding should only happen on success, but the call to env() will get the
- * environment from *before* the new success environment was created. Instead, do:
- * bindAcc(createNode(....))
- */
-Node *GraphBuilder::createAndLinkNode(Operation *op, Node *operands[], size_t opCount,
- bool incomplete)
-{
- Q_ASSERT(op->effectInputCount() < 2);
- Q_ASSERT(op->controlInputCount() < 2);
-
- QVarLengthArray<Node *, 32> inputs(static_cast<int>(opCount));
- std::copy_n(operands, opCount, inputs.data());
-
- if (op->effectInputCount() == 1)
- inputs.append(env()->effectDependency());
- if (op->controlInputCount() == 1)
- inputs.append(env()->controlDependency());
- if (op->hasFrameStateInput())
- inputs.append(env()->createFrameState());
-
- Node *node = m_graph->createNode(op, inputs.data(), inputs.size(), incomplete);
-
- if (op->needsBytecodeOffsets()) {
- m_func->nodeInfo(node)->setBytecodeOffsets(currentInstructionOffset(),
- nextInstructionOffset());
- }
-
- if (op->effectOutputCount() > 0)
- env()->setEffectDependency(node);
- if (op->controlOutputCount() > 0)
- env()->setControlDependency(node);
-
- if (op->canThrow() && env()->unwindHandlerOffset()) {
- InterpreterSubEnvironment successEnv(this);
- Node *control = env()->controlDependency();
- control = m_graph->createNode(opBuilder()->get<Meta::OnException>(), &control, 1);
- env()->setControlDependency(control);
- auto unwindHandlerOffset = env()->unwindHandlerOffset();
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- return node;
-}
-
-Node *GraphBuilder::createNode(Operation *op, bool incomplete)
-{
- return createAndLinkNode(op, nullptr, 0, incomplete);
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1)
-{
- Node *buf[] = { n1 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2)
-{
- Node *buf[] = { n1, n2 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3)
-{
- Node *buf[] = { n1, n2, n3 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4)
-{
- Node *buf[] = { n1, n2, n3, n4 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createRegion(unsigned nControlInputs)
-{
- return createNode(opBuilder()->getRegion(nControlInputs), true);
-}
-
-Node *GraphBuilder::createIfTrue()
-{
- return createNode(opBuilder()->get<Meta::IfTrue>());
-}
-
-Node *GraphBuilder::createIfFalse()
-{
- return createNode(opBuilder()->get<Meta::IfFalse>());
-}
-
-Node *GraphBuilder::createConstant(int v)
-{
- return m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(v)));
-}
-
-Node *GraphBuilder::createPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createEffectPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getEffectPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createHandleUnwind(int offset)
-{
- return createNode(opBuilder()->getHandleUnwind(offset));
-}
-
-Node *GraphBuilder::mergeControl(Node *c1, Node *c2)
-{
- if (c1->operation()->kind() == Meta::Region) {
- const unsigned nInputs = c1->operation()->controlInputCount() + 1;
- c1->addInput(m_graph->pool(), c2);
- c1->setOperation(opBuilder()->getRegion(nInputs));
- return c1;
- }
- auto op = opBuilder()->getRegion(2);
- Node *inputs[] = { c1, c2 };
- return m_graph->createNode(op, inputs, 2);
-}
-
-Node *GraphBuilder::mergeEffect(Node *e1, Node *e2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (e1->operation()->kind() == Meta::EffectPhi && e1->controlInput() == control) {
- e1->insertInput(m_graph->pool(), nInputs - 1, e2);
- e1->setOperation(opBuilder()->getEffectPhi(nInputs));
- return e1;
- }
-
- if (e1 != e2) {
- Node *phi = createEffectPhi(nInputs, e1, control);
- phi->replaceInput(nInputs - 1, e2);
- return phi;
- }
-
- return e1;
-}
-
-Node *GraphBuilder::mergeValue(Node *v1, Node *v2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (v1->operation()->kind() == Meta::Phi && v1->controlInput() == control) {
- v1->insertInput(m_graph->pool(), nInputs - 1, v2);
- v1->setOperation(opBuilder()->getPhi(nInputs));
- return v1;
- }
-
- if (v1 != v2) {
- Node *phi = createPhi(nInputs, v1, control);
- phi->replaceInput(nInputs - 1, v2);
- return phi;
- }
-
- return v1;
-}
-
-Node *GraphBuilder::createToBoolean(Node *input)
-{
- return createNode(opBuilder()->get<Meta::ToBoolean>(), input);
-}
-
-void GraphBuilder::populate(VarArgNodes &args, int argc, int argv)
-{
- for (int i = 0; i < argc; ++i)
- args.append(env()->slot(argv + i));
- Q_ASSERT(argc >= 0 && argc <= std::numeric_limits<uint16_t>::max());
-}
-
-void GraphBuilder::queueFunctionExit(Node *exitNode)
-{
- m_exitControls.push_back(exitNode);
- setEnv(nullptr);
-}
-
-Node *GraphBuilder::mergeIntoSuccessor(int offset)
-{
- InterpreterEnvironment *&successorEnvironment = m_envForOffset[offset];
-
- Node *region = nullptr;
- if (successorEnvironment == nullptr) {
- region = createRegion(1);
- successorEnvironment = env();
- } else {
- // Merge any values which are live coming into the successor.
- region = successorEnvironment->merge(env());
- }
- setEnv(nullptr);
- return region;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::labelInfoAt(unsigned offset) const
-{
- for (const LabelInfo &li : m_labelInfos) {
- if (li.labelOffset == offset)
- return &li;
- }
- return nullptr;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::isLoopStart(unsigned offset) const
-{
- if (auto li = labelInfoAt(offset)) {
- //### in the future, check if this is a loop start, or some other label
- return li;
- }
-
- return nullptr;
-}
-
-void GraphBuilder::handleLoopStart(const LabelInfo &labelInfo)
-{
- Q_ASSERT(env() != nullptr);
-
- // We unconditionally insert a region node with phi nodes here. Now there might already be
- // such a node, (e.g. the region after an if-then-else), but for simplicity we ignore that.
- // A subsequent pass will fold/remove chains of Region nodes.
- //### FIXME: add a DCE pass
-
- const auto offset = int(labelInfo.labelOffset);
- Node *control = createRegion(1);
- env()->setControlDependency(control);
- Node *effect = createEffectPhi(1, env()->effectDependency(), control);
- env()->setEffectDependency(effect);
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = env()->slotCount() - 1; i != ei; ++i) {
- //### use lifeness info to trim this further!
- if (i == CallData::Accumulator)
- continue; // should never be alive on loop entry
- env()->bindNodeToSlot(createPhi(1, env()->slot(i), control), i);
- }
-
- m_envForOffset.insert(offset, env()->copy());
-}
-
-void GraphBuilder::startUnwinding()
-{
- if (int target = env()->unwindHandlerOffset()) {
- mergeIntoSuccessor(target);
- } else {
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
-}
-
-void GraphBuilder::generate_Ret()
-{
- Node* control = createNode(opBuilder()->get<Meta::Return>(), env()->accumulator());
- queueFunctionExit(control);
-}
-
-void GraphBuilder::generate_Debug() { Q_UNREACHABLE(); }
-
-void GraphBuilder::generate_LoadConst(int index)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadZero()
-{
- bindAcc(createConstant(0));
-}
-
-void GraphBuilder::generate_LoadTrue()
-{
- bindAcc(m_graph->trueConstant());
-}
-
-void GraphBuilder::generate_LoadFalse()
-{
- bindAcc(m_graph->falseConstant());
-}
-
-void GraphBuilder::generate_LoadNull()
-{
- bindAcc(m_graph->nullNode());
-}
-
-void GraphBuilder::generate_LoadUndefined()
-{
- bindAcc(m_graph->undefinedNode());
-}
-
-void GraphBuilder::generate_LoadInt(int value)
-{
- bindAcc(m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(value))));
-}
-
-void GraphBuilder::generate_MoveConst(int constIndex, int destTemp)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[constIndex];
- env()->bindNodeToSlot(createNode(opBuilder()->getConstant(v)), destTemp);
-}
-
-void GraphBuilder::generate_LoadReg(int reg)
-{
- bindAcc(env()->slot(reg));
-}
-
-void GraphBuilder::generate_StoreReg(int reg)
-{
- Node *n = env()->accumulator();
- if (reg == CallData::This)
- n = createNode(opBuilder()->get<Meta::StoreThis>(), n);
- env()->bindNodeToSlot(n, reg);
-}
-
-void GraphBuilder::generate_MoveReg(int srcReg, int destReg)
-{
- env()->bindNodeToSlot(env()->slot(srcReg), destReg);
-}
-
-void GraphBuilder::generate_LoadImport(int index)
-{
- auto func = function()->v4Function();
- Value v = *func->compilationUnit->imports[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadLocal(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(0),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreLocal(int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(0),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(scope),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreScopedLocal(int scope, int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(scope),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadRuntimeString(int stringId)
-{
- auto func = function()->v4Function();
- Value v = Value::fromHeapObject(func->compilationUnit->runtimeStrings[stringId]);
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_MoveRegExp(int regExpId, int destReg)
-{
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::LoadRegExp>(),
- createConstant(regExpId)), destReg);
-}
-
-void GraphBuilder::generate_LoadClosure(int value)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadClosure>(),
- createConstant(value)));
-}
-
-void GraphBuilder::generate_LoadName(int name, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadGlobalLookup>(), createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreNameSloppy(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameSloppy>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_StoreNameStrict(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameStrict>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadElement(int base, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadElement>(),
- env()->slot(base),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_StoreElement(int base, int index, int /*traceSlot*/)
-{
- createNode(opBuilder()->get<Meta::JSStoreElement>(),
- env()->slot(base),
- env()->slot(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadProperty(int name, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSLoadProperty>(),
- env()->accumulator(),
- createConstant(name));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_GetLookup(int index, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSGetLookup>(),
- env()->accumulator(),
- createConstant(index));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_StoreProperty(int name, int base)
-{
- createNode(opBuilder()->get<Meta::JSStoreProperty>(),
- env()->slot(base),
- createConstant(name),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_SetLookup(int index, int base)
-{
-
- function()->v4Function()->isStrict()
- ? createNode(opBuilder()->get<Meta::JSSetLookupStrict>(), env()->slot(base),
- createConstant(index), env()->accumulator())
- : createNode(opBuilder()->get<Meta::JSSetLookupSloppy>(), env()->slot(base),
- createConstant(index), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadSuperProperty(int property)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperProperty>(),
- env()->slot(property)));
-}
-
-void GraphBuilder::generate_StoreSuperProperty(int property)
-{
- createNode(opBuilder()->get<Meta::JSStoreSuperProperty>(),
- createConstant(property),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadQmlContextPropertyLookup(int propertyIndex, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::QMLLoadQmlContextPropertyLookup>(),
- createConstant(propertyIndex)));
-}
-
-void GraphBuilder::generate_Yield() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_YieldStar() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_Resume(int /*offset*/) { Q_UNREACHABLE(); }
-
-void GraphBuilder::finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv)
-{
- populate(args, argc, argv);
- bindAcc(createAndLinkNode(opBuilder()->getJSVarArgsCall(kind, uint16_t(args.size())),
- args.data(), size_t(args.size())));
-}
-
-void GraphBuilder::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- finalizeCall(Meta::JSCallValue, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithReceiver, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallProperty, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(lookupIndex));
- finalizeCall(Meta::JSCallLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(env()->slot(index));
- finalizeCall(Meta::JSCallElement, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallName, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSCallPossiblyDirectEval, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::JSCallGlobalLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::QMLCallQmlContextPropertyLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_SetUnwindHandler(int offset)
-{
- m_currentUnwindHandlerOffset = offset ? absoluteOffset(offset) : 0;
- env()->setUnwindHandlerOffset(m_currentUnwindHandlerOffset);
-}
-
-void GraphBuilder::generate_UnwindDispatch()
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
- {
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- startUnwinding();
- }
-
- createIfFalse();
-
- const auto unwindHandlerOffset = env()->unwindHandlerOffset();
- const auto fallthroughSuccessor = nextInstructionOffset();
- auto nContinuations = m_func->unwindLabelOffsets().size() + 1;
- if (unwindHandlerOffset)
- ++nContinuations;
- Q_ASSERT(nContinuations <= std::numeric_limits<unsigned>::max());
- createNode(opBuilder()->getUnwindDispatch(unsigned(nContinuations), unwindHandlerOffset,
- fallthroughSuccessor));
-
- {
- InterpreterSubEnvironment fallthroughEnv(this);
- mergeIntoSuccessor(fallthroughSuccessor);
- }
-
- if (unwindHandlerOffset) {
- InterpreterSubEnvironment unwindHandlerEnv(this);
- createHandleUnwind(unwindHandlerOffset);
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- for (int unwindLabelOffset : m_func->unwindLabelOffsets()) {
- if (unwindLabelOffset <= currentInstructionOffset())
- continue;
- InterpreterSubEnvironment unwindLabelEnv(this);
- createHandleUnwind(unwindLabelOffset);
- mergeIntoSuccessor(unwindLabelOffset);
- }
-
- setEnv(nullptr);
-}
-
-void GraphBuilder::generate_UnwindToLabel(int level, int offset)
-{
- //### For de-optimization, the relative offset probably also needs to be stored
- int unwinder = absoluteOffset(offset);
- createNode(opBuilder()->get<Meta::UnwindToLabel>(),
- createConstant(level),
- createConstant(unwinder));
- m_func->addUnwindLabelOffset(unwinder);
- startUnwinding();
-}
-
-void GraphBuilder::generate_DeadTemporalZoneCheck(int name)
-{
- Node *check = createNode(opBuilder()->get<Meta::IsEmpty>(), env()->accumulator());
- createNode(opBuilder()->get<Meta::Branch>(), check);
-
- { //### it's probably better to handle this by de-optimizing
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- createNode(opBuilder()->get<Meta::ThrowReferenceError>(),
- createConstant(name));
- startUnwinding();
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_ThrowException()
-{
- createNode(opBuilder()->get<Meta::Throw>(), env()->accumulator());
- startUnwinding();
-}
-
-void GraphBuilder::generate_GetException()
-{
- bindAcc(createNode(opBuilder()->get<Meta::GetException>()));
-}
-
-void GraphBuilder::generate_SetException()
-{
- createNode(opBuilder()->get<Meta::SetException>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_CreateCallContext()
-{
- createNode(opBuilder()->get<Meta::JSCreateCallContext>());
-}
-
-void GraphBuilder::generate_PushCatchContext(int index, int name)
-{
- createNode(opBuilder()->get<Meta::JSCreateCatchContext>(),
- createConstant(index),
- createConstant(name));
-}
-
-void GraphBuilder::generate_PushWithContext()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateWithContext>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_PushBlockContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateBlockContext>(),
- createConstant(index));
-}
-
-void GraphBuilder::generate_CloneBlockContext()
-{
- createNode(opBuilder()->get<Meta::JSCloneBlockContext>());
-}
-
-void GraphBuilder::generate_PushScriptContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateScriptContext>(), createConstant(index));
-}
-
-void GraphBuilder::generate_PopScriptContext()
-{
- createNode(opBuilder()->get<Meta::JSPopScriptContext>());
-}
-
-void GraphBuilder::generate_PopContext()
-{
- createNode(opBuilder()->get<Meta::PopContext>());
-}
-
-void GraphBuilder::generate_GetIterator(int iterator)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetIterator>(),
- env()->accumulator(),
- createConstant(iterator)));
-}
-
-void GraphBuilder::generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode,
- int resultSlot)
-{
- // See generate_IteratorNext for why this method exists.
-
- // check that no-one messed around with the operation and made it throwing
- Q_ASSERT(iterationNode->operation()->controlOutputCount() == 1);
-
- // check that it's in the effect chain, because HasException relies on that
- Q_ASSERT(iterationNode->operation()->effectOutputCount() == 1);
-
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::SelectOutput>(),
- iterationNode,
- createConstant(1),
- graph()->undefinedNode()),
- resultSlot);
- // Note: the following will NOT set the accumulator, because it contains the return value of
- // the runtime call!
- Node *ehCheck = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), ehCheck);
-
- { // EH path:
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- if (auto ehOffset = env()->unwindHandlerOffset()) {
- // Ok, there is an exception handler, so go there:
- mergeIntoSuccessor(ehOffset);
- } else {
- // No Exception Handler, so keep the exception set in the engine, and leave the function
- // a.s.a.p.:
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
- }
-
- // Normal control flow:
- createIfFalse();
-}
-
-void GraphBuilder::generate_IteratorNext(int value, int done)
-{
- // The way we model exceptions in the graph is that a runtime function will either succeed and
- // return a value, or it fails and throws an exception. If it throws, the return value is not
- // used because the method did not complete normally, and therefore it might be tainted.
- //
- // This is a problem for (and only for) IteratorNext and IteratorNextForYieldStart.
- //
- // What would happen in the normal case, is that the return value (done) is not used/assigned
- // when IteratorNext throws, because the exception handling path is chosen. However, the
- // interpreter *does* assign it, and will only check for an exception *after* that assignment.
- //
- // So, in order to work around this odd-duck behavior, we mark the operation as NoThrow,
- // override the runtime method and flag it to not throw, and insert extra exception check nodes
- // after the SelectOutput that follows the IteratorNext(ForYieldStar).
- //
- // Also note that the IteratorNext and IteratorNextForYieldStar are the only operations that
- // have an inout parameter, and thus require a SelectOutput node to retrieve this.
-
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNext>(),
- env()->accumulator(),
- graph()->undefinedNode());
- bindAcc(n);
- env()->bindNodeToSlot(n, done);
- generate_IteratorNextAndFriends_TrailingStuff(n, value);
-}
-
-void GraphBuilder::generate_IteratorNextForYieldStar(int iterator, int object)
-{
- // Please, PLEASE read the comment in generate_IteratorNext.
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNextForYieldStar>(),
- env()->accumulator(),
- env()->slot(iterator),
- graph()->undefinedNode());
- // Note: the following is a tiny bit different from what generate_IteratorNext does.
- bindAcc(n);
- generate_IteratorNextAndFriends_TrailingStuff(n, object);
-}
-
-void GraphBuilder::generate_IteratorClose(int done)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIteratorClose>(),
- env()->accumulator(),
- env()->slot(done)));
-}
-
-void GraphBuilder::generate_DestructureRestElement()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDestructureRestElement>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeleteProperty(int base, int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteProperty>(),
- env()->slot(base),
- env()->slot(index)));
-}
-
-void GraphBuilder::generate_DeleteName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofValue()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofValue>(), env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeclareVar(int varName, int isDeletable)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeclareVar>(),
- createConstant(isDeletable),
- createConstant(varName)));
-}
-
-void GraphBuilder::generate_DefineArray(int argc, int argv)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSDefineArray, args, argc, argv);
-}
-
-void GraphBuilder::generate_DefineObjectLiteral(int internalClassId, int argc, int argv)
-{
- VarArgNodes args;
- args.append(createConstant(internalClassId));
- finalizeCall(Meta::JSDefineObjectLiteral, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateClass(int classIndex, int heritage, int computedNames)
-{
- int argc = 0;
- int argv = computedNames;
-
- const QV4::CompiledData::Class *cls = function()->v4Function()->compilationUnit->unitData()
- ->classAt(classIndex);
- const CompiledData::Method *methods = cls->methodTable();
- for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
- if (methods[i].name == std::numeric_limits<unsigned>::max())
- ++argc;
- }
-
- VarArgNodes args;
- args.append(createConstant(classIndex));
- args.append(env()->slot(heritage));
- finalizeCall(Meta::JSCreateClass, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateMappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateMappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateUnmappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateUnmappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateRestParameter(int argIndex)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateRestParameter>(),
- createConstant(argIndex)));
-}
-
-void GraphBuilder::generate_ConvertThisToObject()
-{
- Node* control = createNode(opBuilder()->get<Meta::JSThisToObject>(),
- env()->slot(CallData::This));
- env()->bindNodeToSlot(control, CallData::This);
-}
-
-void GraphBuilder::generate_LoadSuperConstructor()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperConstructor>(),
- env()->slot(CallData::Function)));
-}
-
-void GraphBuilder::generate_ToObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::ToObject>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_TailCall(int func, int thisObject, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- populate(args, argc, argv);
- Node *n = createAndLinkNode(opBuilder()->getJSTailCall(uint16_t(args.size())), args.data(),
- size_t(args.size()));
- queueFunctionExit(n);
-}
-
-void GraphBuilder::generate_Construct(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstruct, args, argc, argv);
-}
-
-void GraphBuilder::generate_ConstructWithSpread(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstructWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_Jump(int offset)
-{
- auto jumpTarget = absoluteOffset(offset);
- mergeIntoSuccessor(jumpTarget);
-}
-
-void GraphBuilder::generate_JumpTrue(int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(env()->accumulator()));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfTrue();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_JumpFalse(int traceSlot, int offset)
-{
- generate_JumpFalse(env()->accumulator(), traceSlot, offset);
-}
-
-void GraphBuilder::generate_JumpFalse(Node *condition, int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(condition));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNoException(int offset)
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNotUndefined(int offset)
-{
- Node *condition = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->accumulator(),
- graph()->undefinedNode());
- generate_JumpFalse(condition, NoTraceSlot, offset);
-}
-
-void GraphBuilder::generate_CmpEqNull()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->accumulator(),
- graph()->nullNode()));
-}
-
-void GraphBuilder::generate_CmpNeNull()
-{
- generate_CmpEqNull();
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEqInt(int lhs)
-{
- auto left = createConstant(lhs);
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- left,
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNeInt(int lhs)
-{
- generate_CmpEqInt(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEq(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNe(int lhs)
-{
- generate_CmpEq(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpGt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpGe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictEqual(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictNotEqual(int lhs)
-{
- generate_CmpStrictEqual(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpIn(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIn>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpInstanceOf(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSInstanceOf>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UNot()
-{
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- createToBoolean(env()->accumulator())));
-}
-
-void GraphBuilder::generate_UPlus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSToNumber>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UMinus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSNegate>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UCompl()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(-1)));
-}
-
-void GraphBuilder::generate_Increment(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-
-void GraphBuilder::generate_Decrement(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-void GraphBuilder::generate_Add(int lhs, int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_BitAnd(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitOr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitXor(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UShr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shl(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-
-void GraphBuilder::generate_BitAndConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitOrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitXorConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_UShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShlConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_Exp(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSExponentiate>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mul(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSMultiply>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Div(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDivide>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mod(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSModulo>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Sub(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
-{
- for (int reg = firstReg; reg < firstReg + count; ++reg)
- env()->bindNodeToSlot(graph()->emptyNode(), reg);
-}
-
-void GraphBuilder::generate_ThrowOnNullOrUndefined()
-{
- createNode(opBuilder()->get<Meta::JSThrowOnNullOrUndefined>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_GetTemplateObject(int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetTemplateObject>(),
- createConstant(index)));
-}
-
-GraphBuilder::Verdict GraphBuilder::startInstruction(Moth::Instr::Type /*instr*/)
-{
- // This handles a couple of cases on how flow control can end up at this instruction.
-
- const auto off = currentInstructionOffset();
- if (auto newEnv = m_envForOffset[off]) {
- // Ok, there was a jump from before to this point (which registered an environment), so we
- // have two options:
- if (env() != newEnv && env() != nullptr) {
- // There is a current environment different from the environment active when we took the
- // jump. This happens with e.g. an if-then-else:
- //
- // acc = condition
- // JumpFalse else-block
- // ... then block
- // Jump end-if
- // else-block:
- // ... else block
- // end-if:
- // .. some instruction <--- we're here
- //
- // in that case we merge the after-else environment into the after-then environment:
- newEnv->merge(env());
- } else {
- // There is not a current environment. This can happen with e.g. a loop:
- // loop-start:
- // acc = condition
- // JumpFalse loop-end
- // ... loop body
- // Jump loop-start
- // loop-end:
- // .... some instruction <--- we're here
- //
- // The last jump of the loop will clear the environment, so at this point we only have
- // the environment registered by the JumpFalse. This is the asy case: no merges, just
- // take the registered environment unchanged.
- }
-
- // Leave the merged environment as-is, and continue with a copy. We cannot change the
- // registered environment in case this point also happens to be a loop start.
- setEnv(newEnv->copy());
- }
-
- if (env() == nullptr) {
- // Ok, there is no environment, meaning nobody jumped to this instruction, and the previous
- // instruction doesn't let control flow end up here. So, this is dead code.
- // This can happen for JS like:
- //
- // if (condition) {
- // return something
- // } else {
- // return somethingElse
- // }
- // someCode <--- we're here
- return SkipInstruction;
- }
-
- const LabelInfo *info = isLoopStart(off);
- if (info && env()) {
- // Ok, this instruction is the start of a loop, meaning there will be a jump backwards to
- // this point. Make sure there is a Region node with Phi nodes here.
- handleLoopStart(*info);
- }
-
- return ProcessInstruction;
-}
-
-void GraphBuilder::endInstruction(Moth::Instr::Type /*instr*/) {}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graphbuilder_p.h b/src/qml/jit/qv4graphbuilder_p.h
deleted file mode 100644
index 450d8640b7..0000000000
--- a/src/qml/jit/qv4graphbuilder_p.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPHBUILDER_P_H
-#define QV4GRAPHBUILDER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4global_p.h>
-#include <private/qv4bytecodehandler_p.h>
-#include <private/qv4ir_p.h>
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// The graph builder walks the byte-code, and produces a graph. The graph is a digraph, where the
-// nodes have operations, and the edges are dependencies (or inputs).
-class GraphBuilder: protected Moth::ByteCodeHandler
-{
- Q_DISABLE_COPY_MOVE(GraphBuilder)
-
- enum { NoTraceSlot = -1 };
-
- struct LabelInfo { //### extend this to also capture the amount of slots that are live
- LabelInfo() = default;
- LabelInfo(unsigned label) : labelOffset(label) {}
- unsigned labelOffset = 0;
- };
-
-public:
- static void buildGraph(IR::Function *function);
-
- class InterpreterEnvironment;
-
- void setEnv(InterpreterEnvironment *newEnv)
- { m_currentEnv = newEnv; }
-
- InterpreterEnvironment *env() const
- { return m_currentEnv; }
-
-private:
- GraphBuilder(IR::Function *function);
- ~GraphBuilder() override = default;
-
- void startGraph();
- void endGraph();
-
- Node *bindAcc(Node *n);
- Node *createAndLinkNode(Operation *op, Node *operands[], size_t opCount, bool incomplete = false);
- Node *createNode(Operation *op, bool incomplete = false);
- Node *createNode(Operation *op, Node *n1);
- Node *createNode(Operation *op, Node *n1, Node *n2);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4);
- Node *createRegion(unsigned nControlInputs);
- Node *createIfTrue();
- Node *createIfFalse();
- Node *createConstant(int v);
- Node *createPhi(unsigned nInputs, Node *input, Node *control);
- Node *createEffectPhi(unsigned nInputs, Node *input, Node *control);
- Node *createHandleUnwind(int offset);
- Node *mergeControl(Node *c1, Node *c2);
- Node *mergeEffect(Node *e1, Node *e2, Node *control);
- Node *mergeValue(Node *v1, Node *v2, Node *control);
-
- Node *createToBoolean(Node *input);
-
- using VarArgNodes = QVarLengthArray<Node *, 32>;
- void populate(VarArgNodes &args, int argc, int argv);
-
- void queueFunctionExit(Node *exitNode);
-
- Function *function() const
- { return m_func; }
-
- Graph *graph()
- { return m_graph; }
-
- Node *mergeIntoSuccessor(int offset);
-
- OperationBuilder *opBuilder() const
- { return m_graph->opBuilder(); }
-
- int absoluteOffset(int offset) const
- { return offset + nextInstructionOffset(); }
-
- const LabelInfo *labelInfoAt(unsigned offset) const;
- const LabelInfo *isLoopStart(unsigned offset) const;
- void handleLoopStart(const LabelInfo &labelInfo);
- void startUnwinding();
-
-protected: // ByteCodeHandler
- void generate_Ret() override;
- void generate_Debug() override;
- void generate_LoadConst(int index) override;
- void generate_LoadZero() override;
- void generate_LoadTrue() override;
- void generate_LoadFalse() override;
- void generate_LoadNull() override;
- void generate_LoadUndefined() override;
- void generate_LoadInt(int value) override;
- void generate_MoveConst(int constIndex, int destTemp) override;
- void generate_LoadReg(int reg) override;
- void generate_StoreReg(int reg) override;
- void generate_MoveReg(int srcReg, int destReg) override;
- void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
- void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
- void generate_StoreScopedLocal(int scope, int index) override;
- void generate_LoadRuntimeString(int stringId) override;
- void generate_MoveRegExp(int regExpId, int destReg) override;
- void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_StoreNameSloppy(int name) override;
- void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
- void generate_StoreProperty(int name, int base) override;
- void generate_SetLookup(int index, int base) override;
- void generate_LoadSuperProperty(int property) override;
- void generate_StoreSuperProperty(int property) override;
- void generate_LoadQmlContextPropertyLookup(int property, int traceSlot) override;
- void generate_Yield() override;
- void generate_YieldStar() override;
- void generate_Resume(int offset) override;
- void finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv);
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_SetUnwindHandler(int offset) override;
- void generate_UnwindDispatch() override;
- void generate_UnwindToLabel(int level, int offset) override;
- void generate_DeadTemporalZoneCheck(int name) override;
- void generate_ThrowException() override;
- void generate_GetException() override;
- void generate_SetException() override;
- void generate_CreateCallContext() override;
- void generate_PushCatchContext(int index, int name) override;
- void generate_PushWithContext() override;
- void generate_PushBlockContext(int index) override;
- void generate_CloneBlockContext() override;
- void generate_PushScriptContext(int index) override;
- void generate_PopScriptContext() override;
- void generate_PopContext() override;
- void generate_GetIterator(int iterator) override;
- void generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode, int resultSlot);
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
- void generate_DestructureRestElement() override;
- void generate_DeleteProperty(int base, int index) override;
- void generate_DeleteName(int name) override;
- void generate_TypeofName(int name) override;
- void generate_TypeofValue() override;
- void generate_DeclareVar(int varName, int isDeletable) override;
- void generate_DefineArray(int argc, int argv) override;
- void generate_DefineObjectLiteral(int internalClassId, int argc, int argv) override;
- void generate_CreateClass(int classIndex, int heritage, int computedNames) override;
- void generate_CreateMappedArgumentsObject() override;
- void generate_CreateUnmappedArgumentsObject() override;
- void generate_CreateRestParameter(int argIndex) override;
- void generate_ConvertThisToObject() override;
- void generate_LoadSuperConstructor() override;
- void generate_ToObject() override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_TailCall(int func, int thisObject, int argc, int argv) override;
- void generate_Construct(int func, int argc, int argv) override;
- void generate_ConstructWithSpread(int func, int argc, int argv) override;
- void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
- void generate_JumpFalse(Node *condition, int traceSlot, int offset);
- void generate_JumpNoException(int offset) override;
- void generate_JumpNotUndefined(int offset) override;
- void generate_CmpEqNull() override;
- void generate_CmpNeNull() override;
- void generate_CmpEqInt(int lhs) override;
- void generate_CmpNeInt(int lhs) override;
- void generate_CmpEq(int lhs) override;
- void generate_CmpNe(int lhs) override;
- void generate_CmpGt(int lhs) override;
- void generate_CmpGe(int lhs) override;
- void generate_CmpLt(int lhs) override;
- void generate_CmpLe(int lhs) override;
- void generate_CmpStrictEqual(int lhs) override;
- void generate_CmpStrictNotEqual(int lhs) override;
- void generate_CmpIn(int lhs) override;
- void generate_CmpInstanceOf(int lhs) override;
- void generate_UNot() override;
- void generate_UPlus(int traceSlot) override;
- void generate_UMinus(int traceSlot) override;
- void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
- void generate_BitAnd(int lhs) override;
- void generate_BitOr(int lhs) override;
- void generate_BitXor(int lhs) override;
- void generate_UShr(int lhs) override;
- void generate_Shr(int lhs) override;
- void generate_Shl(int lhs) override;
- void generate_BitAndConst(int rhs) override;
- void generate_BitOrConst(int rhs) override;
- void generate_BitXorConst(int rhs) override;
- void generate_UShrConst(int rhs) override;
- void generate_ShrConst(int rhs) override;
- void generate_ShlConst(int rhs) override;
- void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
- void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
- void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
- void generate_ThrowOnNullOrUndefined() override;
- void generate_GetTemplateObject(int index) override;
-
- Verdict startInstruction(Moth::Instr::Type instr) override;
- void endInstruction(Moth::Instr::Type instr) override;
-
-private:
- IR::Function *m_func;
- Graph *m_graph;
- InterpreterEnvironment *m_currentEnv;
- std::vector<Node *> m_exitControls;
- QHash<int, InterpreterEnvironment *> m_envForOffset;
- std::vector<LabelInfo> m_labelInfos;
- int m_currentUnwindHandlerOffset = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPHBUILDER_P_H
diff --git a/src/qml/jit/qv4ir.cpp b/src/qml/jit/qv4ir.cpp
deleted file mode 100644
index cb3eeeec60..0000000000
--- a/src/qml/jit/qv4ir.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qqmlglobal_p.h>
-#include "qv4ir_p.h"
-#include "qv4node_p.h"
-#include "qv4function_p.h"
-#include <qv4graph_p.h>
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-#include "qv4util_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qfile.h>
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcJsonIR, "qt.v4.ir.json");
-Q_LOGGING_CATEGORY(lcDotIR, "qt.v4.ir.dot");
-Q_LOGGING_CATEGORY(lcVerify, "qt.v4.ir.verify");
-
-Function::Function(QV4::Function *qv4Function)
- : qv4Function(qv4Function)
- , m_graph(Graph::create(this))
- , m_dumper(nullptr)
- , m_nodeInfo(128, nullptr)
-{
-}
-
-Function::~Function()
-{
- delete m_dumper;
-}
-
-QString Function::name() const
-{
- QString name;
- if (auto n = v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- name = QString::asprintf("%p", v4Function());
- auto loc = v4Function()->sourceLocation();
- return name + QStringLiteral(" (%1:%2:%3)").arg(loc.sourceFile, QString::number(loc.line),
- QString::number(loc.column));
-}
-
-void Function::dump(const QString &description) const
-{
- Dumper::dump(this, description);
-}
-
-void Function::dump() const
-{
- dump(QStringLiteral("Debug:"));
-}
-
-Dumper *Function::dumper() const
-{
- if (!m_dumper)
- m_dumper = new Dumper(this);
- return m_dumper;
-}
-
-Function::StringId Function::addString(const QString &s)
-{
- m_stringPool.push_back(s);
- return m_stringPool.size() - 1;
-}
-
-NodeInfo *Function::nodeInfo(Node *n, bool createIfNecessary) const
-{
- if (n->id() >= m_nodeInfo.size())
- m_nodeInfo.resize(n->id() * 2, nullptr);
-
- NodeInfo *&info = m_nodeInfo[n->id()];
- if (info == nullptr && createIfNecessary) {
- info = m_pool.New<NodeInfo>();
- info->setType(n->operation()->type());
- }
- return info;
-}
-
-void Function::copyBytecodeOffsets(Node *from, Node *to)
-{
- auto toInfo = nodeInfo(to);
- if (auto fromInfo = nodeInfo(from)) {
- toInfo->setBytecodeOffsets(fromInfo->currentInstructionOffset(),
- fromInfo->nextInstructionOffset());
- }
-}
-
-Dumper::Dumper(const Function *f)
-{
- if (!f)
- return;
-}
-
-void Dumper::dump(const Function *f, const QString &description)
-{
- if (false && lcJsonIR().isDebugEnabled()) {
- Dumper *dumper = f->dumper();
-
- qCDebug(lcJsonIR).noquote().nospace() << description + QLatin1String(":\n");
- for (const auto &line : dumper->dump(f).split('\n'))
- qCDebug(lcJsonIR).noquote().nospace() << line;
- }
-
- if (lcDotIR().isDebugEnabled())
- dot(f, description);
-}
-
-QByteArray Dumper::dump(const Function *f)
-{
- QJsonObject fo;
-
- {
- QString name;
- if (auto n = f->v4Function()->name())
- name = n->toQString();
- fo[QLatin1String("_searchKey")] = QStringLiteral("function %1").arg(name);
- if (name.isEmpty())
- name = QString::asprintf("%p", f->v4Function());
- fo[QLatin1String("name")] = name;
- }
-
- auto loc = f->v4Function()->sourceLocation();
- fo[QLatin1String("source")] = loc.sourceFile;
- fo[QLatin1String("line")] = loc.line;
- fo[QLatin1String("column")] = loc.column;
-
- {
- QJsonArray gn;
- QJsonArray ge;
- NodeCollector nodes(f->graph(), /*collectUses =*/ true);
- nodes.sortById();
- for (Node *n : nodes.reachable()) {
- gn.append(dump(n, f));
- int inputIndex = 0;
- for (Node *input : n->inputs()) {
- QJsonObject edge;
- edge[QLatin1String("from")] = int(input->id());
- edge[QLatin1String("to")] = int(n->id());
- edge[QLatin1String("index")] = inputIndex;
- if (inputIndex < n->operation()->valueInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("value");
- } else if (inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("effect");
- } else {
- edge[QLatin1String("type")] = QLatin1String("control");
- }
- Q_ASSERT(inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()
- + n->operation()->controlInputCount());
- ge.append(edge);
- ++inputIndex;
- }
- }
- QJsonObject g;
- g[QLatin1String("nodes")] = gn;
- g[QLatin1String("edges")] = ge;
- fo[QLatin1String("graph")] = g;
- }
-
- m_doc.setObject(fo);
- return m_doc.toJson(QJsonDocument::Indented);
-}
-
-QJsonValue toJSonValue(QV4::Value v)
-{
- switch (v.type()) {
- case QV4::Value::Undefined_Type: return QJsonValue(QJsonValue::Undefined);
- case QV4::Value::Null_Type: return QJsonValue(QJsonValue::Null);
- case QV4::Value::Boolean_Type: return QJsonValue(v.booleanValue());
- case QV4::Value::Integer_Type: return QJsonValue(v.int_32());
- case QV4::Value::Managed_Type:
- if (String *s = v.stringValue())
- return QJsonValue(s->toQString());
- else
- return QJsonValue(QLatin1String("<managed>"));
- default: return QJsonValue(v.doubleValue());
- }
-}
-
-QJsonValue Dumper::dump(const Node * const node, const Function *f)
-{
- QJsonObject n;
- n[QLatin1String("id")] = int(node->id());
- n[QLatin1String("kind")] = node->operation()->debugString();
- switch (node->operation()->kind()) {
- case Meta::Parameter: {
- auto info = ParameterPayload::get(*node->operation());
- n[QLatin1String("name")] = f->string(info->stringId());
- n[QLatin1String("index")] = int(info->parameterIndex());
- break;
- }
- case Meta::Constant: {
- auto info = ConstantPayload::get(*node->operation());
- n[QLatin1String("value")] = toJSonValue(info->value());
- break;
- }
- default:
- break;
- }
- return n;
-}
-
-void Dumper::dot(const Function *f, const QString &description)
-{
- static const bool skipFramestate = qEnvironmentVariableIsSet("QV4_JIT_DOT_SKIP_FRAMESTATE");
-
- auto node = [](Node *n) {
- return QStringLiteral("n%1[label=\"%1: %2%3\"];\n").arg(QString::number(n->id()),
- n->operation()->debugString(),
- n->isDead() ? QStringLiteral(" (dead)")
- : QString());
- };
-
- Graph *g = f->graph();
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"n%1\" label=\"%2\";"
- "node[shape=rect];"
- "edge[dir=back fontsize=10];\n")
- .arg(g->startNode()->id())
- .arg(description);
- out += node(g->startNode());
- const bool dumpUses = false; // set to true to see all nodes
- NodeCollector nodes(g, dumpUses, skipFramestate);
- for (Node *n : nodes.reachable()) {
- if (n == g->startNode())
- continue;
-
- out += node(n);
-
- unsigned inputIndex = 0;
- for (Node *input : n->inputs()) {
- if (input == nullptr)
- continue;
- out += QStringLiteral("n%2->n%1[style=").arg(QString::number(n->id()),
- QString::number(input->id()));
- if (inputIndex < n->operation()->valueInputCount() ||
- inputIndex == n->operation()->indexOfFrameStateInput()) {
- out += QStringLiteral("solid headlabel=\"%1\"").arg(inputIndex);
- } else if (inputIndex < unsigned(n->operation()->valueInputCount()
- + n->operation()->effectInputCount())) {
- out += QStringLiteral("dotted headlabel=\"%1\"").arg(inputIndex);
- } else {
- out += QStringLiteral("dashed headlabel=\"%1\"").arg(inputIndex);
- }
- out += QStringLiteral("];\n");
- ++inputIndex;
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotIR).nospace().noquote() << out;
-
- QFile of(description + QStringLiteral(".dot"));
- of.open(QIODevice::WriteOnly);
- of.write(out.toUtf8());
- of.close();
-}
-
-void Function::verify() const
-{
-#ifndef QT_NO_DEBUG
- unsigned problemsFound = 0;
-
- auto verifyNodeAgainstOperation = [&problemsFound](const Node *n) {
- const Operation *op = n->operation();
- if (op->totalInputCount() != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Node" << n->id() << "has" << n->inputCount()
- << "inputs, but it's operation" << op->debugString()
- << "requires" << op->totalInputCount() << "inputs";
- }
-
- if (n->opcode() == Meta::Phi || n->opcode() == Meta::EffectPhi) {
- if (n->controlInput()->opcode() != Meta::Region) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id() << "is not a region";
- }
- if (n->controlInput()->inputCount() + 1 != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id()
- << "has" << n->controlInput()->inputCount()
- << "inputs while phi node has" << n->inputCount()
- << "inputs";
- }
- }
-
- //### todo: verify outputs: value outputs are allowed to be unused, but the effect and
- // control outputs have to be linked up, except:
- //### todo: verify if no use is a nullptr, except for operations that can throw, where the
- // last one is allowed to be a nullptr when an unwind handler is missing.
- };
-
- NodeWorkList todo(graph());
- todo.enqueue(graph()->endNode());
- while (Node *n = todo.dequeueNextNodeForVisiting()) {
- todo.enqueueAllInputs(n);
- todo.enqueueAllUses(n);
-
- verifyNodeAgainstOperation(n);
- }
- //### TODO:
- if (problemsFound != 0) {
- dump(QStringLiteral("Problematic graph"));
- qFatal("Found %u problems during graph verification!", problemsFound);
- }
-#endif // QT_NO_xDEBUG
-}
-
-QString Type::debugString() const
-{
- if (isNone())
- return QStringLiteral("none");
- if (isInvalid())
- return QStringLiteral("invalid");
-
- QStringList s;
- if (m_t & Bool)
- s += QStringLiteral("boolean");
- if (m_t & Int32)
- s += QStringLiteral("int32");
- if (m_t & Double)
- s += QStringLiteral("double");
- if (m_t & Undefined)
- s += QStringLiteral("undefined");
- if (m_t & Null)
- s += QStringLiteral("null");
- if (m_t & Empty)
- s += QStringLiteral("empty");
- if (m_t & RawPointer)
- s += QStringLiteral("raw pointer");
-
- return s.join(QLatin1String(" "));
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4ir_p.h b/src/qml/jit/qv4ir_p.h
deleted file mode 100644
index e21a80528d..0000000000
--- a/src/qml/jit/qv4ir_p.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4IR_P_H
-#define QV4IR_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4function_p.h>
-#include <QtCore/qjsondocument.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Dumper;
-class Graph;
-
-class Node;
-class NodeInfo;
-
-class Function
-{
- Q_DISABLE_COPY_MOVE(Function)
-public:
- Function(QV4::Function *qv4Function);
- ~Function();
-
- void verify() const;
-
- QV4::Function *v4Function() const
- { return qv4Function; }
-
- QString name() const;
-
- QQmlJS::MemoryPool *pool()
- { return &m_pool; }
-
- Graph *graph() const
- { return m_graph; }
-
- void dump(const QString &description) const;
- void dump() const; // for calling in the debugger
- Dumper *dumper() const;
-
- using StringId = size_t;
- StringId addString(const QString &s);
- QString string(StringId id) const
- { return m_stringPool[id]; }
-
- NodeInfo *nodeInfo(Node *n, bool createIfNecessary = true) const;
- void copyBytecodeOffsets(Node *from, Node *to);
-
- void addUnwindLabelOffset(int absoluteOffset)
- { m_unwindLabelOffsets.push_back(absoluteOffset); }
-
- const std::vector<int> &unwindLabelOffsets() const
- { return m_unwindLabelOffsets; }
-
-private:
- QV4::Function *qv4Function;
- mutable QQmlJS::MemoryPool m_pool;
- Graph *m_graph;
- mutable Dumper *m_dumper;
- std::vector<QString> m_stringPool;
- mutable std::vector<NodeInfo *> m_nodeInfo; //### move the into the _pool
- std::vector<int> m_unwindLabelOffsets;
-};
-
-class Dumper
-{
- Q_DISABLE_COPY_MOVE(Dumper)
-
-public:
- Dumper(const Function *f);
- ~Dumper() = default;
-
- static void dump(const Function *f, const QString &description);
- static void dot(const Function *f, const QString &description);
-
-private:
- QByteArray dump(const Function *f);
- QJsonValue dump(const Node *node, const Function *f);
-
-private:
- QJsonDocument m_doc;
-};
-
-class Type
-{
- // None is for nodes with no type (e.g. a Return)
- // The others form a lattice:
- // Any -> Object -> Invalid
- // ^^^ -> Number -> Integral -> Int32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> UInt32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> Bool -> ^^^^^^^
- // ^^^ -> Number -> Double -> ^^^^^^^
- // ^^^ -> Undefined -> ^^^^^^^
- // ^^^ -> Null -> ^^^^^^^
- // ^^^ -> Empty -> ^^^^^^^
- enum InternalType: int16_t {
- None = 0,
-
- Object = 1 << 0,
- Bool = 1 << 1,
- Int32 = 1 << 2,
- UInt32 = 1 << 3,
- Double = 1 << 4,
- Undefined = 1 << 5,
- Null = 1 << 6,
- Empty = 1 << 7,
- RawPointer = 1 << 8,
- Invalid = -1,
-
- Integral = Int32 | UInt32 | Bool,
- Number = Integral | Double,
- Any = Object | Number | Undefined | Empty | Null,
- };
-
- Type(InternalType t) : m_t(t) {}
-
-public:
- Type() = default;
-
- bool operator==(const Type &other) const
- { return m_t == other.m_t; }
-
- static Type noneType() { return Type(None); }
- static Type anyType() { return Type(Any); }
- static Type undefinedType() { return Type(Undefined); }
- static Type emptyType() { return Type(Empty); }
- static Type booleanType() { return Type(Bool); }
- static Type int32Type() { return Type(Int32); }
- static Type doubleType() { return Type(Double); }
- static Type numberType() { return Type(Number); }
- static Type nullType() { return Type(Null); }
- static Type objectType() { return Type(Object); }
- static Type rawPointerType() { return Type(RawPointer); }
-
- bool isAny() const { return m_t == Any; }
- bool isBoolean() const { return m_t == Bool; }
- bool isInt32() const { return m_t == Int32; }
- bool isInvalid() const { return m_t == Invalid; }
- bool isNone() const { return m_t == None; }
- bool isDouble() const { return m_t == Double; }
- bool isUndefined() const { return m_t == Undefined; }
- bool isNull() const { return m_t == Null; }
- bool isEmpty() const { return m_t == Empty; }
- bool isObject() const { return m_t == Object; }
- bool isRawPointer() const { return m_t == RawPointer; }
- bool isIntegral() const { return matches(Integral); }
- bool isNumber() const { return matches(Number); }
-
- Type operator|(Type other) const
- { return Type(InternalType(int16_t(m_t) | int16_t(other.m_t))); }
-
- Type &operator|=(Type other)
- {
- m_t = (InternalType(int16_t(m_t) | int16_t(other.m_t)));
- return *this;
- }
-
- QString debugString() const;
-
-private:
- bool matches(InternalType it) const
- {
- return (m_t & ~it) == 0 && (m_t & it) != 0;
- }
-
-private:
- InternalType m_t = None;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4IR_P_H
diff --git a/src/qml/jit/qv4loopinfo.cpp b/src/qml/jit/qv4loopinfo.cpp
deleted file mode 100644
index 0366c49e30..0000000000
--- a/src/qml/jit/qv4loopinfo.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4loopinfo_p.h"
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLoopinfo, "qt.v4.ir.loopinfo")
-
-void LoopInfo::detectLoops()
-{
- blockInfos.resize(dt.function()->blockCount());
-
- std::vector<MIBlock *> backedges;
- backedges.reserve(4);
-
- const auto order = dt.calculateDFNodeIterOrder();
- for (MIBlock *bb : order) {
- if (bb->isDeoptBlock())
- continue;
-
- backedges.clear();
-
- for (MIBlock *pred : bb->inEdges()) {
- if (bb == pred || dt.dominates(bb->index(), pred->index()))
- backedges.push_back(pred);
- }
-
- if (!backedges.empty())
- subLoop(bb, backedges);
- }
-
- collectLoopExits();
-
- dump();
-}
-
-void LoopInfo::collectLoopExits()
-{
- for (MIBlock::Index i = 0, ei = MIBlock::Index(blockInfos.size()); i != ei; ++i) {
- BlockInfo &bi = blockInfos[i];
- MIBlock *currentBlock = dt.function()->block(i);
- if (bi.isLoopHeader) {
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != currentBlock && !inLoopOrSubLoop(outEdge, currentBlock))
- bi.loopExits.push_back(outEdge);
- }
- }
- if (MIBlock *containingLoop = bi.loopHeader) {
- BlockInfo &loopInfo = blockInfos[containingLoop->index()];
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != containingLoop && !inLoopOrSubLoop(outEdge, containingLoop))
- loopInfo.loopExits.push_back(outEdge);
- }
- }
- }
-}
-
-bool LoopInfo::inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const
-{
- const BlockInfo &bi = blockInfos[block->index()];
- MIBlock *loopHeaderForBlock = bi.loopHeader;
- if (loopHeaderForBlock == nullptr)
- return false; // block is not in any loop
-
- while (loopHeader) {
- if (loopHeader == loopHeaderForBlock)
- return true;
- // look into the parent loop of loopHeader to see if block is contained there
- loopHeader = blockInfos[loopHeader->index()].loopHeader;
- }
-
- return false;
-}
-
-void LoopInfo::subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges)
-{
- blockInfos[loopHead->index()].isLoopHeader = true;
-
- std::vector<MIBlock *> worklist;
- worklist.reserve(backedges.size() + 8);
- worklist.insert(worklist.end(), backedges.begin(), backedges.end());
- while (!worklist.empty()) {
- MIBlock *predIt = worklist.back();
- worklist.pop_back();
-
- MIBlock *subloop = blockInfos[predIt->index()].loopHeader;
- if (subloop) {
- // This is a discovered block. Find its outermost discovered loop.
- while (MIBlock *parentLoop = blockInfos[subloop->index()].loopHeader)
- subloop = parentLoop;
-
- // If it is already discovered to be a subloop of this loop, continue.
- if (subloop == loopHead)
- continue;
-
- // Yay, it's a subloop of this loop.
- blockInfos[subloop->index()].loopHeader = loopHead;
- predIt = subloop;
-
- // Add all predecessors of the subloop header to the worklist, as long as
- // those predecessors are not in the current subloop. It might be the case
- // that they are in other loops, which we will then add as a subloop to the
- // current loop.
- for (MIBlock *predIn : predIt->inEdges())
- if (blockInfos[predIn->index()].loopHeader != subloop)
- worklist.push_back(predIn);
- } else {
- if (predIt == loopHead)
- continue;
-
- // This is an undiscovered block. Map it to the current loop.
- blockInfos[predIt->index()].loopHeader = loopHead;
-
- // Add all incoming edges to the worklist.
- for (MIBlock *bb : predIt->inEdges())
- worklist.push_back(bb);
- }
- }
-}
-
-void LoopInfo::dump() const
-{
- if (!lcLoopinfo().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Loop information:\n");
- for (size_t i = 0, ei = blockInfos.size(); i != ei; ++i) {
- const BlockInfo &bi = blockInfos[i];
- s += QStringLiteral(" %1 : is loop header: %2, contained in loop header's loop: ")
- .arg(i).arg(bi.isLoopHeader ? QLatin1String("yes") : QLatin1String("no"));
- if (bi.loopHeader)
- s += QString::number(bi.loopHeader->index());
- else
- s += QLatin1String("<none>");
- if (bi.isLoopHeader) {
- s += QStringLiteral(", loop exits: ");
- if (bi.loopExits.empty()) {
- s += QLatin1String("<none>");
- } else {
- bool first = true;
- for (MIBlock *exit : bi.loopExits) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QString::number(exit->index());
- }
- }
- }
- s += QLatin1Char('\n');
- }
- qCDebug(lcLoopinfo).noquote().nospace() << s;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4loopinfo_p.h b/src/qml/jit/qv4loopinfo_p.h
deleted file mode 100644
index 6a865e6dc6..0000000000
--- a/src/qml/jit/qv4loopinfo_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOOPINFO_P_H
-#define QV4LOOPINFO_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-
-#include <QHash>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-
-// Detect all (sub-)loops in a function.
-//
-// Doing loop detection on the CFG is better than relying on the statement information in
-// order to mark loops. Although JavaScript only has natural loops, it can still be the case
-// that something is not a loop even though a loop-like-statement is in the source. For
-// example:
-// while (true) {
-// if (i > 0)
-// break;
-// else
-// break;
-// }
-//
-// Algorithm:
-// - do a DFS on the dominator tree, where for each node:
-// - collect all back-edges
-// - if there are back-edges, the node is a loop-header for a new loop, so:
-// - walk the CFG is reverse-direction, and for every node:
-// - if the node already belongs to a loop, we've found a nested loop:
-// - get the loop-header for the (outermost) nested loop
-// - add that loop-header to the current loop
-// - continue by walking all incoming edges that do not yet belong to the current loop
-// - if the node does not belong to a loop yet, add it to the current loop, and
-// go on with all incoming edges
-//
-// Loop-header detection by checking for back-edges is very straight forward: a back-edge is
-// an incoming edge where the other node is dominated by the current node. Meaning: all
-// execution paths that reach that other node have to go through the current node, that other
-// node ends with a (conditional) jump back to the loop header.
-//
-// The exact order of the DFS on the dominator tree is not important. The only property has to
-// be that a node is only visited when all the nodes it dominates have been visited before.
-// The reason for the DFS is that for nested loops, the inner loop's loop-header is dominated
-// by the outer loop's header. So, by visiting depth-first, sub-loops are identified before
-// their containing loops, which makes nested-loop identification free. An added benefit is
-// that the nodes for those sub-loops are only processed once.
-//
-// Note: independent loops that share the same header are merged together. For example, in
-// the code snippet below, there are 2 back-edges into the loop-header, but only one single
-// loop will be detected.
-// while (a) {
-// if (b)
-// continue;
-// else
-// continue;
-// }
-class LoopInfo
-{
- Q_DISABLE_COPY_MOVE(LoopInfo)
-
- struct BlockInfo
- {
- MIBlock *loopHeader = nullptr;
- bool isLoopHeader = false;
- std::vector<MIBlock *> loopExits;
- };
-
-public:
- LoopInfo(const DominatorTree &dt)
- : dt(dt)
- {}
-
- ~LoopInfo() = default;
-
- void detectLoops();
-
- MIBlock *loopHeaderFor(MIBlock *bodyBlock) const
- { return blockInfos[bodyBlock->index()].loopHeader; }
-
- bool isLoopHeader(MIBlock *block) const
- { return blockInfos[block->index()].isLoopHeader; }
-
- const std::vector<MIBlock *> loopExitsForLoop(MIBlock *loopHeader) const
- { return blockInfos[loopHeader->index()].loopExits; }
-
-private:
- void subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges);
- void collectLoopExits();
- bool inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const;
-
- void dump() const;
-
-private:
- const DominatorTree &dt;
- std::vector<BlockInfo> blockInfos;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOOPINFO_P_H
diff --git a/src/qml/jit/qv4lowering.cpp b/src/qml/jit/qv4lowering.cpp
deleted file mode 100644
index 3b3711e7fa..0000000000
--- a/src/qml/jit/qv4lowering.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QLoggingCategory>
-
-#include "qv4lowering_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLower, "qt.v4.ir.lowering")
-
-GenericLowering::GenericLowering(Function &f)
- : m_function(f)
-{}
-
-void GenericLowering::lower()
-{
- NodeWorkList worklist(graph());
- // The order doesn't really matter for generic lowering, as long as it's done in 1 pass, and
- // have any clean-up done afterwards.
- worklist.enqueueAllInputs(graph()->endNode());
-
- while (Node *n = worklist.dequeueNextNodeForVisiting()) {
- worklist.enqueueAllInputs(n);
-
- if (!CallPayload::isRuntimeCall(n->opcode()))
- continue;
-
- if (CallPayload::isVarArgsCall(n->opcode()))
- replaceWithVarArgsCall(n);
- else
- replaceWithCall(n);
- }
-}
-
-void GenericLowering::replaceWithCall(Node *n)
-{
- auto newOp = opBuilder()->getCall(n->opcode());
-
- QVarLengthArray<Node *, 32> args;
- if (CallPayload::takesEngineAsArg(n->opcode(), 0))
- args.append(graph()->engineNode());
- if (CallPayload::takesFunctionAsArg(n->opcode(), args.size()))
- args.append(graph()->functionNode());
- if (CallPayload::takesFrameAsArg(n->opcode(), args.size()))
- args.append(graph()->cppFrameNode());
- const int extraLeadingArguments = args.size();
-
- for (unsigned arg = 0, earg = n->inputCount(); arg != earg; ++arg) {
- Node *input = n->input(arg);
- if (input->opcode() == Meta::FrameState)
- continue;
-
- if (arg >= n->operation()->valueInputCount()) {
- // effect or control input
- args.append(input);
- continue;
- }
-
- if (CallPayload::needsStorageOnJSStack(n->opcode(), args.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
-
- args.append(input);
- }
-
- Node *newCall = graph()->createNode(newOp, args.data(), args.size());
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- function().nodeInfo(newCall)->setType(CallPayload::returnType(n->opcode()));
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-
- for (Node *use : newCall->uses()) {
- // fix-up indices for SelectOutput:
- if (use->opcode() == Meta::SelectOutput) {
- const int oldIndex = ConstantPayload::get(*use->input(1)->operation())->value().int_32();
- const int newIndex = oldIndex + extraLeadingArguments;
- use->replaceInput(1, graph()->createConstantIntNode(newIndex));
- use->replaceInput(2, newCall->input(newIndex));
- break;
- }
- }
-}
-
-void GenericLowering::replaceWithVarArgsCall(Node *n)
-{
- const bool isTailCall = n->opcode() == Meta::JSTailCall;
- Operation *newOp = isTailCall ? opBuilder()->getTailCall()
- : opBuilder()->getCall(n->opcode());
-
- //### optimize this for 0 and 1 argument: we don't need to create a VarArgs array for these cases
-
- const unsigned varArgsStart = CallPayload::varArgsStart(n->opcode()) - 1; // subtract 1 because the runtime calls all take the engine argument as arg0, which isn't in the graph before lowering.
- Node *vaAlloc = graph()->createNode(
- opBuilder()->get<Meta::VAAlloc>(),
- graph()->createConstantIntNode(n->operation()->valueInputCount() - varArgsStart),
- n->effectInput());
- QVarLengthArray<Node *, 32> vaSealIn;
- vaSealIn.append(vaAlloc);
- for (unsigned i = varArgsStart, ei = n->operation()->valueInputCount(); i != ei; ++i) {
- vaSealIn.append(graph()->createNode(opBuilder()->get<Meta::VAStore>(), vaAlloc,
- graph()->createConstantIntNode(vaSealIn.size() - 1),
- n->input(i)));
- }
- vaSealIn.append(vaAlloc);
- Node *vaSeal = graph()->createNode(opBuilder()->getVASeal(vaSealIn.size() - 2),
- vaSealIn.data(),
- vaSealIn.size());
- QVarLengthArray<Node *, 8> callArgs;
- if (isTailCall)
- callArgs.append(graph()->cppFrameNode());
- callArgs.append(graph()->engineNode());
- for (unsigned i = 0; i != varArgsStart; ++i) {
- Node *input = n->input(i);
- if (CallPayload::needsStorageOnJSStack(n->opcode(), callArgs.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
- callArgs.append(input);
- }
- callArgs.append(vaSeal); // args
- if (n->opcode() != Meta::JSCreateClass) // JSCreateClass is the odd duck
- callArgs.append(graph()->createConstantIntNode(vaSealIn.size() - 2)); // argc
- callArgs.append(vaSeal); // effect
- callArgs.append(n->controlInput(0)); // control flow
- Node *newCall = graph()->createNode(newOp, callArgs.data(), unsigned(callArgs.size()));
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-}
-
-bool GenericLowering::allUsesAsUnboxedBool(Node *n)
-{
- for (Node *use : n->uses()) {
- if (use->operation()->kind() != Meta::Branch)
- return false;
- }
-
- return true;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4lowering_p.h b/src/qml/jit/qv4lowering_p.h
deleted file mode 100644
index 0b482bc9f0..0000000000
--- a/src/qml/jit/qv4lowering_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOWERING_P_H
-#define QV4LOWERING_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4util_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4graph_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Lowering replaces JS level operations with lower level ones. E.g. a JSAdd is lowered to an AddI32
-// if both inputs and the output are 32bit integers, or to a runtime call in all other cases. This
-// transforms the graph into something that is closer to actual executable code.
-
-
-// Last lowering phase: replace all JSOperations that are left with runtime calls. There is nothing
-// smart here, all that should have been done before this phase.
-class GenericLowering final
-{
- Q_DISABLE_COPY(GenericLowering)
-
-public:
- GenericLowering(Function &f);
-
- void lower();
-
-private:
- void replaceWithCall(Node *n);
- void replaceWithVarArgsCall(Node *n);
- static bool allUsesAsUnboxedBool(Node *n);
-
- Function &function()
- { return m_function; }
-
- Graph *graph()
- { return function().graph(); }
-
- OperationBuilder *opBuilder()
- { return graph()->opBuilder(); }
-
-private:
- Function &m_function;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOWERING_P_H
diff --git a/src/qml/jit/qv4mi.cpp b/src/qml/jit/qv4mi.cpp
deleted file mode 100644
index f0b172243d..0000000000
--- a/src/qml/jit/qv4mi.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <private/qqmlglobal_p.h>
-
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcMI, "qt.v4.ir.mi")
-
-QString MIOperand::debugString() const
-{
- switch (kind()) {
- case Invalid: return QStringLiteral("<<INVALID>>");
- case Constant: return ConstantPayload::debugString(constantValue());
- case VirtualRegister: return QStringLiteral("vreg%1").arg(virtualRegister());
- case EngineRegister: return QStringLiteral("engine");
- case CppFrameRegister: return QStringLiteral("cppFrame");
- case Function: return QStringLiteral("function");
- case JSStackSlot: return QStringLiteral("jsstack[%1]").arg(stackSlot());
- case BoolStackSlot: return QStringLiteral("bstack[%1]").arg(stackSlot());
- case JumpTarget: return targetBlock() ? QStringLiteral("L%1").arg(targetBlock()->index())
- : QStringLiteral("<<INVALID BLOCK>>");
- default: Q_UNREACHABLE();
- }
-}
-
-MIInstr *MIInstr::create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands)
-{
- return pool->New<MIInstr>(irNode, pool, nOperands);
-}
-
-static QString commentIndent(const QString &line)
-{
- int spacing = std::max(70 - line.length(), 1);
- return line + QString(spacing, QLatin1Char(' '));
-}
-
-static QString indent(int nr)
-{
- QString s = nr == -1 ? QString() : QString::number(nr);
- int padding = 6 - s.size();
- if (padding > 0)
- s = QString(padding, QLatin1Char(' ')) + s;
- return s;
-}
-
-MIFunction::MIFunction(Function *irFunction)
- : m_irFunction(irFunction)
-{}
-
-void MIFunction::renumberBlocks()
-{
- for (size_t i = 0, ei = m_blocks.size(); i != ei; ++i) {
- MIBlock *b = m_blocks[i];
- b->setIndex(unsigned(i));
- }
-}
-
-void MIFunction::renumberInstructions()
-{
- int pos = 0;
- for (MIBlock *b : m_blocks) {
- for (MIInstr &instr : b->instructions()) {
- pos += 2;
- instr.setPosition(pos);
- }
- }
-}
-
-void MIFunction::dump(const QString &description) const
-{
- if (!lcMI().isDebugEnabled())
- return;
-
- QString s = description + QLatin1String(":\n");
- QString name;
- if (auto n = irFunction()->v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- QString::asprintf("%p", static_cast<void *>(irFunction()->v4Function()));
- QString line = QStringLiteral("function %1 {").arg(name);
- auto loc = irFunction()->v4Function()->sourceLocation();
- s += commentIndent(line) + QStringLiteral("; %1:%2:%3\n").arg(loc.sourceFile,
- QString::number(loc.line),
- QString::number(loc.column));
- for (const MIBlock *b : blocks()) {
- line = QStringLiteral("L%1").arg(b->index());
- bool first = true;
- if (!b->arguments().empty()) {
- line += QLatin1Char('(');
- for (const MIOperand &arg : b->arguments()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += arg.debugString();
- }
- line += QLatin1Char(')');
- }
- line += QLatin1Char(':');
- line = commentIndent(line) + QStringLiteral("; preds: ");
- if (b->inEdges().isEmpty()) {
- line += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *in : b->inEdges()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += QStringLiteral("L%1").arg(in->index());
- }
- }
- s += line + QLatin1Char('\n');
- for (const MIInstr &i : b->instructions()) {
- line = indent(i.position()) + QLatin1String(": ");
- if (i.hasDestination())
- line += i.destination().debugString() + QStringLiteral(" = ");
- line += i.irNode()->operation()->debugString();
- bool first = true;
- for (const MIOperand &op : i.operands()) {
- if (first)
- first = false;
- else
- line += QLatin1Char(',');
- line += QLatin1Char(' ') + op.debugString();
- }
- line = commentIndent(line) + QStringLiteral("; node-id: %1").arg(i.irNode()->id());
- if (i.irNode()->operation()->needsBytecodeOffsets())
- line += QStringLiteral(", bytecode-offset: %1").arg(irFunction()->nodeInfo(i.irNode())->currentInstructionOffset());
- s += line + QLatin1Char('\n');
- }
- s += commentIndent(QString()) + QStringLiteral("; succs: ");
- if (b->outEdges().isEmpty()) {
- s += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *succ : b->outEdges()) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QStringLiteral("L%1").arg(succ->index());
- }
- }
- s += QLatin1Char('\n');
- }
- s += QLatin1Char('}');
-
- for (const QStringRef &line : s.splitRef('\n'))
- qCDebug(lcMI).noquote().nospace() << line;
-}
-
-unsigned MIFunction::extraJSSlots() const
-{
- uint interpreterFrameSize = CppStackFrame::requiredJSStackFrameSize(irFunction()->v4Function());
- if (m_jsSlotCount <= interpreterFrameSize)
- return 0;
- return m_jsSlotCount - interpreterFrameSize;
-}
-
-void MIFunction::setStartBlock(MIBlock *newStartBlock)
-{
- auto it = std::find(m_blocks.begin(), m_blocks.end(), newStartBlock);
- Q_ASSERT(it != m_blocks.end());
- std::swap(*m_blocks.begin(), *it);
-}
-
-void MIFunction::setStackSlotCounts(unsigned dword, unsigned qword, unsigned js)
-{
- m_vregCount = 0;
- m_dwordSlotCount = dword;
- m_qwordSlotCount = qword;
- m_jsSlotCount = js;
-}
-
-void MIFunction::verifyCFG() const
-{
- if (block(MIFunction::StartBlockIndex)->instructions().front().opcode() != Meta::Start)
- qFatal("MIFunction block 0 is not the start block");
-
- for (MIBlock *b : m_blocks) {
- for (MIBlock *in : b->inEdges()) {
- if (!in->outEdges().contains(b))
- qFatal("block %u has incoming edge from block %u, "
- "but does not appear in that block's outgoing edges",
- b->index(), in->index());
- }
- for (MIBlock *out : b->outEdges()) {
- if (!out->inEdges().contains(b))
- qFatal("block %u has outgoing edge from block %u, "
- "but does not appear in that block's incoming edges",
- b->index(), out->index());
- }
- }
-}
-
-MIBlock *MIBlock::findEdgeTo(Operation::Kind target) const
-{
- for (MIBlock *outEdge : outEdges()) {
- if (outEdge->instructions().front().opcode() == target)
- return outEdge;
- }
- return nullptr;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4mi_p.h b/src/qml/jit/qv4mi_p.h
deleted file mode 100644
index f976d1dc94..0000000000
--- a/src/qml/jit/qv4mi_p.h
+++ /dev/null
@@ -1,627 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MI_P_H
-#define QV4MI_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4operation_p.h>
-
-#include <llvm/ADT/iterator.h>
-#include <llvm/ADT/iterator_range.h>
-#include <llvm/ADT/ilist.h>
-#include <llvm/ADT/ilist_node.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// This file contains the Machine Interface (MI) data structures, on which ultimately the assembler
-// will operate:
-
-class MIFunction; // containing all basic blocks, and a reference to the IR function
-
-class MIBlock; // containing an ordered sequence of instructions
-
-class MIInstr; // containing operands, and a reference to the IR node, that indicates which
- // operation is represented by an instruction
-
-class MIOperand; // contains a description of where to get/put the input/result of an operation
-
-// A detail about the stack slots: there two stacks, the JS stack and the native stack. A frame on
-// the native stack is divided in two parts: the quad-word part and the double-word part. The
-// qword part holds 64bit values, like doubles, and pointers on 64bit architectures. The dword part
-// holds 32bit values, like int32s, booleans, and pointers on 32bit architectures. We need to know
-// the type of value a slot holds, because if we have to move it to the JS stack, we have to box it
-// correctly.
-class MIOperand final
-{
-public:
- enum Kind {
- Invalid = 0,
- Constant,
- VirtualRegister,
-
- EngineRegister,
- CppFrameRegister,
- Function,
-
- JSStackSlot,
- BoolStackSlot,
-
- JumpTarget,
- };
-
- using List = QQmlJS::FixedPoolArray<MIOperand>;
-
-public:
- MIOperand() = default;
-
- static MIOperand createConstant(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Constant;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createVirtualRegister(Node *irNode, unsigned vreg)
- {
- MIOperand op;
- op.m_kind = VirtualRegister;
- op.m_irNode = irNode;
- op.m_vreg = vreg;
- return op;
- }
-
- static MIOperand createEngineRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = EngineRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createCppFrameRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = CppFrameRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createFunction(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Function;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createJSStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = JSStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- static MIOperand createBoolStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = BoolStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- //### or name this createDeoptBlock?
- static MIOperand createJumpTarget(Node *irNode, MIBlock *targetBlock)
- {
- MIOperand op;
- op.m_kind = JumpTarget;
- op.m_irNode = irNode;
- op.m_targetBlock = targetBlock;
- return op;
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isValid() const
- { return m_kind != Invalid; }
-
- bool isConstant() const
- { return m_kind == Constant; }
-
- bool isVirtualRegister() const
- { return kind() == VirtualRegister; }
-
- bool isEngineRegister() const
- { return kind() == EngineRegister; }
-
- bool isCppFrameRegister() const
- { return kind() == CppFrameRegister; }
-
- bool isFunction() const
- { return kind() == Function; }
-
- bool isJSStackSlot() const
- { return kind() == JSStackSlot; }
-
- bool isBoolStackSlot() const
- { return kind() == BoolStackSlot; }
-
- bool isStackSlot() const
- { return isJSStackSlot() || isDWordSlot() || isQWordSlot(); }
-
- bool isJumpTarget() const
- { return kind() == JumpTarget; }
-
- Node *irNode() const
- { return m_irNode; }
-
- inline Type nodeType(MIFunction *f) const;
-
- QString debugString() const;
-
- QV4::Value constantValue() const
- {
- Q_ASSERT(isConstant());
- if (irNode()->opcode() == Meta::Undefined)
- return QV4::Value::undefinedValue();
- if (irNode()->opcode() == Meta::Empty)
- return QV4::Value::emptyValue();
- return ConstantPayload::get(*irNode()->operation())->value();
- }
-
- unsigned virtualRegister() const
- { Q_ASSERT(isVirtualRegister()); return m_vreg; }
-
- unsigned stackSlot() const
- { Q_ASSERT(isStackSlot()); return m_slot; }
-
- MIBlock *targetBlock() const
- { Q_ASSERT(isJumpTarget()); return m_targetBlock; }
-
- inline bool operator==(const MIOperand &other) const
- {
- if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- switch (kind()) {
- case MIOperand::Invalid:
- return !other.isValid();
- case MIOperand::Constant:
- return constantValue().asReturnedValue() == other.constantValue().asReturnedValue();
- case MIOperand::VirtualRegister:
- return virtualRegister() == other.virtualRegister();
- case MIOperand::JumpTarget:
- return targetBlock() == other.targetBlock();
- default:
- Q_UNREACHABLE();
- return false;
- }
- }
-
- bool isDWordSlot() const
- {
- switch (kind()) {
- case BoolStackSlot:
- return true;
- default:
- return false;
- }
- }
-
- bool isQWordSlot() const
- {
- switch (kind()) {
- //### TODO: double slots
- default:
- return false;
- }
- }
-
- bool overlaps(const MIOperand &other) const
- {
- if ((isDWordSlot() && other.isDWordSlot()) || (isQWordSlot() && other.isQWordSlot()))
- ; // fine, these are the same
- else if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- return false;
- }
-
-private:
- Node *m_irNode = nullptr;
- union {
- unsigned m_vreg;
- unsigned m_slot;
- MIBlock *m_targetBlock = nullptr;
- };
- Kind m_kind = Invalid;
-};
-
-template <typename NodeTy> struct MIInstrListParentType {};
-template <> struct MIInstrListParentType<MIInstr> { using type = MIBlock; };
-
-template <typename NodeTy> class MIInstrList;
-
-template <typename MISubClass>
-class MIInstrListTraits : public llvm::ilist_noalloc_traits<MISubClass>
-{
-protected:
- using ListTy = MIInstrList<MISubClass>;
- using iterator = typename llvm::simple_ilist<MISubClass>::iterator;
- using ItemParentClass = typename MIInstrListParentType<MISubClass>::type;
-
-public:
- MIInstrListTraits() = default;
-
-protected:
- void setListOwner(ItemParentClass *listOwner)
- { m_owner = listOwner; }
-
-private:
- ItemParentClass *m_owner = nullptr;
-
- /// getListOwner - Return the object that owns this list. If this is a list
- /// of instructions, it returns the BasicBlock that owns them.
- ItemParentClass *getListOwner() const {
- return m_owner;
- }
-
- static ListTy &getList(ItemParentClass *Par) {
- return Par->*(Par->getSublistAccess());
- }
-
- static MIInstrListTraits<MISubClass> *getSymTab(ItemParentClass *Par) {
- return Par ? toPtr(Par->getValueSymbolTable()) : nullptr;
- }
-
-public:
- void addNodeToList(MISubClass *V) { V->setParent(getListOwner()); }
- void removeNodeFromList(MISubClass *V) { V->setParent(nullptr); }
- void transferNodesFromList(MIInstrListTraits &L2, iterator first,
- iterator last);
-};
-
-template <class T>
-class MIInstrList: public llvm::iplist_impl<llvm::simple_ilist<T>, MIInstrListTraits<T>>
-{
-public:
- MIInstrList(typename MIInstrListTraits<T>::ItemParentClass *owner)
- { this->setListOwner(owner); }
-};
-
-class MIInstr final : public llvm::ilist_node_with_parent<MIInstr, MIBlock>
-{
- Q_DISABLE_COPY_MOVE(MIInstr) // heap use only!
-
-protected:
- friend class QQmlJS::MemoryPool;
- MIInstr() : m_operands(nullptr, 0) {}
-
- explicit MIInstr(Node *irNode, QQmlJS::MemoryPool *pool, unsigned nOperands)
- : m_irNode(irNode)
- , m_operands(pool, nOperands)
- {}
-
- ~MIInstr() = default;
-
-public:
- static MIInstr *create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands);
-
- MIBlock *parent() const
- { return m_parent; }
-
- MIBlock *getParent() const // for ilist_node_with_parent
- { return parent(); }
-
- void setParent(MIBlock *parent)
- { m_parent = parent; }
-
- Node *irNode() const
- { return m_irNode; }
-
- Operation::Kind opcode() const
- { return m_irNode->opcode(); }
-
- int position() const
- { return m_position; }
-
- inline void insertBefore(MIInstr *insertPos);
- inline void insertAfter(MIInstr *insertPos);
- inline MIInstrList<MIInstr>::iterator eraseFromParent();
-
- bool hasDestination() const
- { return m_destination.isValid(); }
-
- MIOperand destination() const
- { return m_destination; }
-
- void setDestination(const MIOperand &dest)
- { m_destination = dest; }
-
- const MIOperand &operand(unsigned index) const
- { return m_operands.at(index); }
-
- void setOperand(unsigned index, const MIOperand &op)
- { m_operands.at(index) = op; }
-
- MIOperand &operand(unsigned index)
- { return m_operands.at(index); }
-
- const MIOperand::List &operands() const
- { return m_operands; }
-
- MIOperand::List &operands()
- { return m_operands; }
-
-private:
- friend MIFunction;
- void setPosition(int newPosition)
- { m_position = newPosition; }
-
-private:
- MIBlock *m_parent = nullptr;
- Node *m_irNode = nullptr;
- int m_position = -1;
- MIOperand m_destination;
- MIOperand::List m_operands;
-};
-
-class MIBlock final
-{
- Q_DISABLE_COPY_MOVE(MIBlock)
-
-public:
- using Index = unsigned;
- enum : Index { InvalidIndex = std::numeric_limits<Index>::max() };
-
- using MIInstructionList = MIInstrList<MIInstr>;
-
- using InEdges = QVarLengthArray<MIBlock *, 4>;
- using OutEdges = QVarLengthArray<MIBlock *, 2>;
-
-protected:
- friend MIFunction;
- explicit MIBlock(Index index)
- : m_instructions(this),
- m_index(index)
- {}
-
- void setIndex(Index newIndex)
- { m_index = newIndex; }
-
-public:
- ~MIBlock() = default;
-
- const MIInstructionList &instructions() const
- { return m_instructions; }
-
- MIInstructionList &instructions()
- { return m_instructions; }
-
- static MIInstructionList MIBlock::*getSublistAccess(MIInstr * = nullptr)
- { return &MIBlock::m_instructions; }
-
- void addArgument(MIOperand &&arg)
- { m_arguments.push_back(arg); }
-
- const std::vector<MIOperand> &arguments() const
- { return m_arguments; }
-
- std::vector<MIOperand> &arguments()
- { return m_arguments; }
-
- void clearArguments()
- { m_arguments.resize(0); }
-
- const InEdges &inEdges() const
- { return m_inEdges; }
-
- void addInEdge(MIBlock *edge)
- { m_inEdges.append(edge); }
-
- const OutEdges &outEdges() const
- { return m_outEdges; }
-
- void addOutEdge(MIBlock *edge)
- { m_outEdges.append(edge); }
-
- Index index() const
- { return m_index; }
-
- MIBlock *findEdgeTo(Operation::Kind target) const;
-
- bool isDeoptBlock() const
- { return m_isDeoptBlock; }
-
- void markAsDeoptBlock()
- { m_isDeoptBlock = true; }
-
-private:
- std::vector<MIOperand> m_arguments;
- MIInstructionList m_instructions;
- InEdges m_inEdges;
- OutEdges m_outEdges;
- Index m_index;
- bool m_isDeoptBlock = false;
-};
-
-class MIFunction final
-{
- Q_DISABLE_COPY_MOVE(MIFunction)
-
-public:
- static constexpr MIBlock::Index StartBlockIndex = 0;
-
-public:
- MIFunction(Function *irFunction);
- ~MIFunction()
- { qDeleteAll(m_blocks); }
-
- Function *irFunction() const
- { return m_irFunction; }
-
- void setStartBlock(MIBlock *newStartBlock);
- void renumberBlocks();
- void renumberInstructions();
-
- void dump(const QString &description) const;
-
- size_t blockCount() const
- { return blocks().size(); }
-
- MIBlock *block(MIBlock::Index index) const
- { return m_blocks[index]; }
-
- const std::vector<MIBlock *> &blocks() const
- { return m_blocks; }
-
- MIBlock *addBlock()
- {
- auto *b = new MIBlock(unsigned(m_blocks.size()));
- m_blocks.push_back(b);
- return b;
- }
-
- void setBlockOrder(const std::vector<MIBlock *> &newSequence)
- { m_blocks = newSequence; }
-
- unsigned vregCount() const
- { return m_vregCount; }
-
- void setVregCount(unsigned vregCount)
- { m_vregCount = vregCount; }
-
- unsigned dwordSlotCount() const
- { return m_dwordSlotCount; }
-
- unsigned qwordSlotCount() const
- { return m_qwordSlotCount; }
-
- unsigned jsSlotCount() const
- { return m_jsSlotCount; }
-
- unsigned extraJSSlots() const;
-
- void setStackSlotCounts(unsigned dword, unsigned qword, unsigned js);
-
- void verifyCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- std::vector<MIBlock *> m_blocks;
- unsigned m_vregCount = 0;
- unsigned m_dwordSlotCount = 0;
- unsigned m_qwordSlotCount = 0;
- unsigned m_jsSlotCount = 0;
-};
-
-Type MIOperand::nodeType(MIFunction *f) const
-{
- return f->irFunction()->nodeInfo(irNode())->type();
-}
-
-inline uint qHash(const MIOperand &key, uint seed)
-{
- uint h = ::qHash(key.kind(), seed);
- switch (key.kind()) {
- case MIOperand::VirtualRegister:
- h ^= key.virtualRegister();
- break;
- case MIOperand::BoolStackSlot: Q_FALLTHROUGH();
- case MIOperand::JSStackSlot:
- h ^= key.stackSlot();
- break;
- default:
- qFatal("%s: cannot hash %s", Q_FUNC_INFO, key.debugString().toUtf8().constData());
- }
- return h;
-}
-
-void MIInstr::insertBefore(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(insertPos->getIterator(), this);
-}
-
-void MIInstr::insertAfter(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(++insertPos->getIterator(), this);
-}
-
-MIInstrList<MIInstr>::iterator MIInstr::eraseFromParent()
-{
- auto p = parent();
- setParent(nullptr);
- return p->instructions().erase(getIterator());
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MI_P_H
diff --git a/src/qml/jit/qv4miblockset_p.h b/src/qml/jit/qv4miblockset_p.h
deleted file mode 100644
index 5f814b99e0..0000000000
--- a/src/qml/jit/qv4miblockset_p.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MIBLOCKSET_P_H
-#define QV4MIBLOCKSET_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class MIBlockSet
-{
- using Flags = BitVector;
-
- QVarLengthArray<MIBlock::Index, 8> blockNumbers;
- Flags *blockFlags = nullptr;
- MIFunction *function = nullptr;
- enum { MaxVectorCapacity = 8 };
-
-public:
- class const_iterator;
- friend class const_iterator;
-
-public:
- MIBlockSet(MIFunction *f = nullptr)
- {
- if (f)
- init(f);
- }
-
- MIBlockSet(MIBlockSet &&other) noexcept
- {
- std::swap(blockNumbers, other.blockNumbers);
- std::swap(blockFlags, other.blockFlags);
- std::swap(function, other.function);
- }
-
- MIBlockSet(const MIBlockSet &other)
- : function(other.function)
- {
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- }
-
- MIBlockSet &operator=(const MIBlockSet &other)
- {
- if (blockFlags) {
- delete blockFlags;
- blockFlags = nullptr;
- }
- function = other.function;
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- return *this;
- }
-
- MIBlockSet &operator=(MIBlockSet &&other) noexcept
- {
- if (&other != this) {
- std::swap(blockNumbers, other.blockNumbers);
-
- delete blockFlags;
- blockFlags = other.blockFlags;
- other.blockFlags = nullptr;
-
- function = other.function;
- }
- return *this;
- }
-
- ~MIBlockSet()
- {
- delete blockFlags;
- }
-
- void init(MIFunction *f)
- {
- Q_ASSERT(!function);
- Q_ASSERT(f);
- function = f;
- }
-
- bool empty() const;
-
- void insert(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->setBit(bb->index());
- return;
- }
-
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- if (blockNumber == bb->index())
- return;
- }
-
- if (blockNumbers.size() == MaxVectorCapacity) {
- blockFlags = new Flags(int(function->blockCount()), false);
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- blockFlags->setBit(int(blockNumber));
- }
- blockNumbers.clear();
- blockFlags->setBit(int(bb->index()));
- } else {
- blockNumbers.append(bb->index());
- }
- }
-
- void remove(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->clearBit(bb->index());
- return;
- }
-
- for (int i = 0; i < blockNumbers.size(); ++i) {
- if (blockNumbers[i] == bb->index()) {
- blockNumbers.remove(i);
- return;
- }
- }
- }
-
- const_iterator begin() const;
- const_iterator end() const;
-
- void collectValues(std::vector<MIBlock *> &bbs) const;
-
- bool contains(MIBlock *bb) const
- {
- Q_ASSERT(function);
-
- if (blockFlags)
- return blockFlags->at(bb->index());
-
- for (unsigned int blockNumber : blockNumbers) {
- if (blockNumber == bb->index())
- return true;
- }
-
- return false;
- }
-};
-
-class MIBlockSet::const_iterator
-{
- const MIBlockSet &set;
- // ### These two members could go into a union, but clang won't compile
- // (https://codereview.qt-project.org/#change,74259)
- QVarLengthArray<MIBlock::Index, 8>::const_iterator numberIt;
- MIBlock::Index flagIt;
-
- friend class MIBlockSet;
- const_iterator(const MIBlockSet &set, bool end)
- : set(set)
- {
- if (end || !set.function) {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.end();
- else
- flagIt = set.blockFlags->size();
- } else {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.begin();
- else
- findNextWithFlags(0);
- }
- }
-
- void findNextWithFlags(int start)
- {
- flagIt = MIBlock::Index(set.blockFlags->findNext(start, true, /*wrapAround = */false));
- Q_ASSERT(flagIt <= MIBlock::Index(set.blockFlags->size()));
- }
-
-public:
- MIBlock *operator*() const
- {
- if (!set.blockFlags)
- return set.function->block(*numberIt);
-
- Q_ASSERT(flagIt <= set.function->blockCount());
- return set.function->block(flagIt);
-
- }
-
- bool operator==(const const_iterator &other) const
- {
- if (&set != &other.set)
- return false;
- if (!set.blockFlags)
- return numberIt == other.numberIt;
- return flagIt == other.flagIt;
- }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- {
- if (!set.blockFlags)
- ++numberIt;
- else
- findNextWithFlags(flagIt + 1);
-
- return *this;
- }
-};
-
-inline bool MIBlockSet::empty() const
-{ return begin() == end(); }
-
-inline MIBlockSet::const_iterator MIBlockSet::begin() const
-{ return const_iterator(*this, false); }
-
-inline MIBlockSet::const_iterator MIBlockSet::end() const
-{ return const_iterator(*this, true); }
-
-inline void MIBlockSet::collectValues(std::vector<MIBlock *> &bbs) const
-{
- Q_ASSERT(function);
-
- for (auto it : *this)
- bbs.push_back(it);
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MIBLOCKSET_P_H
diff --git a/src/qml/jit/qv4node.cpp b/src/qml/jit/qv4node.cpp
deleted file mode 100644
index e059e9fef6..0000000000
--- a/src/qml/jit/qv4node.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4node_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Node *Node::create(Node::MemoryPool *pool, Node::Id id, const Operation *op, size_t nInputs,
- Node *const *inputs, bool inputsAreExtensible)
-{
- size_t capacity = nInputs;
- if (inputsAreExtensible)
- capacity += 3;
-
- Node *node = new (pool->allocate(sizeof(Node))) Node(pool, id, op, unsigned(nInputs),
- int(capacity));
- for (uint i = 0; i < capacity; ++i)
- new (&node->m_inputs[int(i)]) Use(node);
- for (size_t i = 0; i < nInputs; ++i) {
- Q_ASSERT(inputs[i] != nullptr);
- node->replaceInput(unsigned(i), inputs[i]);
- }
-
- return node;
-}
-
-void Node::addInput(MemoryPool *pool, Node *in)
-{
- Q_ASSERT(in);
- ++m_nInputs;
- if (m_nInputs >= unsigned(m_inputs.size())) {
- QQmlJS::FixedPoolArray<Use> oldInputs = m_inputs;
- m_inputs = QQmlJS::FixedPoolArray<Use>(pool, int(m_nInputs + 3));
- for (Use &input : m_inputs)
- new (&input) Use(this);
- for (int i = 0, ei = oldInputs.size(); i != ei; ++i) {
- Node *in = oldInputs[i].m_input;
- oldInputs[i].set(nullptr);
- m_inputs[i].set(in);
- }
- }
- m_inputs.at(int(m_nInputs - 1)).set(in);
-}
-
-void Node::removeInput(unsigned index)
-{
- Q_ASSERT(index < inputCount());
- for (unsigned i = index, ei = inputCount(); i < ei - 1; ++i)
- replaceInput(i, input(i + 1));
- trimInputCount(inputCount() - 1);
-}
-
-void Node::removeInputs(unsigned start, unsigned count)
-{
- for (unsigned idx = start; idx < start + count; ++idx)
- m_inputs.at(int(idx)).set(nullptr);
-}
-
-void Node::removeAllInputs()
-{
- removeInputs(0, inputCount());
-}
-
-void Node::trimInputCount(unsigned newCount)
-{
- unsigned currentCount = inputCount();
- if (newCount == currentCount)
- return;
- Q_ASSERT(newCount < currentCount);
- removeInputs(newCount, currentCount - newCount);
- m_nInputs = newCount;
-}
-
-void Node::removeExceptionHandlerUse()
-{
- for (Use* use = m_firstUse; use; use = use->m_next) {
- if (use->m_input->opcode() == Meta::OnException) {
- use->set(nullptr);
- break;
- }
- }
-}
-
-void Node::insertInput(Node::MemoryPool *pool, unsigned index, Node *newInput)
-{
- Q_ASSERT(index < inputCount());
- addInput(pool, input(inputCount() - 1));
- for (unsigned i = inputCount() - 1; i > index; --i)
- replaceInput(i, input(i - 1));
- replaceInput(index, newInput);
-}
-
-void Node::replaceAllUsesWith(Node *replacement)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const unsigned inIdx = use->inputIndex();
- use->user()->replaceInput(inIdx, replacement);
- use = next;
- }
-}
-
-void Node::replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const Operation *inOp = use->user()->operation();
- const unsigned inIdx = use->inputIndex();
- if (inIdx < inOp->valueInputCount())
- use->user()->replaceInput(inIdx, newValueInput);
- else if (inIdx < inOp->indexOfFirstControl())
- use->user()->replaceInput(inIdx, newEffectInput);
- else
- use->user()->replaceInput(inIdx, newControlInput);
- use = next;
- }
-}
-
-Node *Node::firstValueUse()
-{
- for (auto it = uses().begin(), eit = uses().end(); it != eit; ++it) {
- if (it.isUsedAsValue())
- return *it;
- }
- return nullptr;
-}
-
-Node::Node(MemoryPool *pool, Node::Id id, const Operation *op, unsigned nInputs, int capacity)
- : m_op(op)
- , m_inputs(pool, capacity)
- , m_nInputs(nInputs)
- , m_id(id)
-{
-}
-
-NodeWorkList::NodeWorkList(const Graph *g)
- : m_nodeState(g->nodeCount(), Unvisited)
-{ m_worklist.reserve(64); }
-
-void NodeWorkList::reset()
-{
- std::fill(m_nodeState.begin(), m_nodeState.end(), Unvisited);
- m_worklist.clear();
- if (m_worklist.capacity() < 64)
- m_worklist.reserve(64);
-}
-
-NodeCollector::NodeCollector(const Graph *g, bool collectUses, bool skipFramestate)
-{
- markReachable(g->endNode());
- for (size_t i = 0; i < m_reachable.size(); ++i) { // _reachable.size() is on purpose!
- Node *n = m_reachable.at(i);
- for (auto input : n->inputs()) {
- if (input == nullptr)
- continue;
- if (isReachable(input->id()))
- continue;
- if (skipFramestate && input->opcode() == Meta::FrameState)
- continue;
- markReachable(input);
- }
-
- if (collectUses) {
- for (Node *use : n->uses()) {
- if (use && !isReachable(use->id()))
- markReachable(use);
- }
- }
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4node_p.h b/src/qml/jit/qv4node_p.h
deleted file mode 100644
index 76065fb1bc..0000000000
--- a/src/qml/jit/qv4node_p.h
+++ /dev/null
@@ -1,626 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4NODE_P_H
-#define QV4NODE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4operation_p.h>
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Use
-{
- Q_DISABLE_COPY_MOVE(Use)
-
-public:
- Use(Node *user)
- : m_user(user)
- {}
-
- ~Use()
- {
- if (m_input)
- removeFromList();
- }
-
- operator Node *() const { return m_input; }
- Node *input() const { return m_input; }
- Node *user() const { return m_user; }
-
- inline void set(Node *newInput);
-
- void validate() const
- {
- Q_ASSERT(m_user);
- if (m_input) {
- if (m_prev != nullptr)
- Q_ASSERT(*m_prev == this);
- if (m_next) {
- Q_ASSERT(m_next->m_input == m_input);
- Q_ASSERT(m_next->m_prev == &m_next);
- m_next->validate();
- }
- }
- }
-
- inline int inputIndex() const;
-
-protected:
- friend class Node;
-
- void addToList(Use **list) {
- validate();
- m_next = *list;
- if (m_next)
- m_next->m_prev = &m_next;
- m_prev = list;
- *list = this;
- validate();
- }
-
- void removeFromList() {
- validate();
- Use **newPrev = m_prev;
- *newPrev = m_next;
- m_prev = nullptr;
- if (m_next)
- m_next->m_prev = newPrev;
- m_next = nullptr;
- m_input = nullptr;
- validate();
- }
-
-private:
- Node *m_input = nullptr;
- Node *m_user = nullptr;
- Use *m_next = nullptr;
- Use **m_prev = nullptr;
-};
-
-// A node represents an calculation, action, or marker in the graph. Each node has an operation,
-// input dependencies and uses. The operation indicates what kind of node it is, e.g.: JSAdd,
-// Constant, Region, and so on. Two nodes can have the same operation, but different inputs.
-// For example, the expressions 1 + 2 and 3 + 4 will each have a node with an JSAdd operation
-// (which is exactly the same operation for both nodes), but the nodes have different inputs (1, and
-// 2 in the first expression, while the second operation has 3 and 4 as inputs).
-class Node final
-{
- Q_DISABLE_COPY_MOVE(Node)
-
-public:
- using Id = uint32_t;
- using MemoryPool = QQmlJS::MemoryPool;
- class Inputs;
-
-public:
- static Node *create(MemoryPool *pool, Id id, const Operation *op, size_t nInputs,
- Node * const *inputs, bool inputsAreExtensible = false);
- ~Node() = delete;
-
- inline bool isDead() const;
- inline void kill();
-
- Id id() const { return m_id; }
-
- const Operation *operation() const
- { return m_op; }
-
- void setOperation(const Operation *op)
- { m_op = op; }
-
- Operation::Kind opcode() const
- { return operation()->kind(); }
-
- inline Inputs inputs() const;
- void addInput(MemoryPool *pool, Node *in);
- void removeInput(unsigned index);
- void removeInputs(unsigned start, unsigned count);
- void removeAllInputs();
- uint32_t inputCount() const
- { return m_nInputs; }
- void trimInputCount(unsigned newCount);
-
- void removeExceptionHandlerUse();
-
- Node *input(unsigned idx) const
- {
- Q_ASSERT(idx < inputCount());
- return m_inputs.at(idx);
- }
-
- Node *effectInput(unsigned effectIndex = 0) const
- {
- if (operation()->effectInputCount() == 0)
- return nullptr;
- Q_ASSERT(effectIndex < operation()->effectInputCount());
- return input(operation()->indexOfFirstEffect() + effectIndex);
- }
-
- Node *controlInput(unsigned controlIndex = 0) const
- {
- if (operation()->controlInputCount() == 0)
- return nullptr;
- Q_ASSERT(controlIndex < operation()->controlInputCount());
- return input(operation()->indexOfFirstControl() + controlIndex);
- }
-
- Node *frameStateInput() const
- {
- if (operation()->hasFrameStateInput())
- return input(operation()->indexOfFrameStateInput());
- return nullptr;
- }
-
- void setFrameStateInput(Node *newFramestate)
- {
- if (operation()->hasFrameStateInput())
- replaceInput(operation()->indexOfFrameStateInput(), newFramestate);
- }
-
- void insertInput(MemoryPool *pool, unsigned index, Node *newInput);
-
- void replaceInput(Node *oldIn, Node *newIn)
- {
- for (unsigned i = 0, ei = inputCount(); i != ei; ++i) {
- if (input(i) == oldIn)
- replaceInput(i, newIn);
- }
- }
-
- void replaceInput(unsigned idx, Node *newIn)
- {
- m_inputs[idx].set(newIn);
- }
-
- class Uses
- {
- public:
- explicit Uses(Node *node)
- : m_node(node)
- {}
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool isEmpty() const;
-
- private:
- Node *m_node;
- };
-
- Uses uses() { return Uses(this); }
- bool hasUses() const { return m_firstUse != nullptr; }
- unsigned useCount() const
- {
- unsigned cnt = 0;
- for (Use *it = m_firstUse; it; it = it->m_next)
- ++cnt;
- return cnt;
- }
- void replaceAllUsesWith(Node *replacement);
- void replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput);
-
- Node *firstValueUse();
-
-private: // types and utility methods
- friend class Use;
- Node(MemoryPool *pool, Id id, const Operation *op, unsigned nInputs, int capacity);
-
-private: // fields
- Use *m_firstUse = nullptr;
- const Operation *m_op = nullptr;
- QQmlJS::FixedPoolArray<Use> m_inputs;
- unsigned m_nInputs = 0;
- Id m_id = 0;
-};
-
-void Use::set(Node *newInput)
-{
- if (m_input)
- removeFromList();
- m_input = newInput;
- if (newInput)
- addToList(&newInput->m_firstUse);
-}
-
-class Node::Inputs final
-{
-public:
- using value_type = Node *;
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool empty() const
- { return m_nInputs == 0; }
-
- unsigned count() const
- { return m_nInputs; }
-
- explicit Inputs(const Use *inputs, unsigned nInputs)
- : m_inputs(inputs), m_nInputs(nInputs)
- {}
-
-private:
- const Use *m_inputs = nullptr;
- unsigned m_nInputs = 0;
-};
-
-class Node::Inputs::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using value_type = Node *;
- using pointer = const value_type *;
- using reference = value_type &;
-
- Node *operator*() const
- { return m_inputs->m_input; }
-
- bool operator==(const const_iterator &other) const
- { return m_inputs == other.m_inputs; }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- { ++m_inputs; return *this; }
-
- const_iterator& operator+=(difference_type offset)
- { m_inputs += offset; return *this; }
-
- const_iterator operator+(difference_type offset) const
- { return const_iterator(m_inputs + offset); }
-
- difference_type operator-(const const_iterator &other) const
- { return m_inputs - other.m_inputs; }
-
-private:
- friend class Node::Inputs;
-
- explicit const_iterator(const Use *inputs)
- : m_inputs(inputs)
- {}
-
- const Use *m_inputs;
-};
-
-Node::Inputs::const_iterator Node::Inputs::begin() const
-{ return const_iterator(m_inputs); }
-
-Node::Inputs::const_iterator Node::Inputs::end() const
-{ return const_iterator(m_inputs + m_nInputs); }
-
-Node::Inputs Node::inputs() const
-{
- return Inputs(m_inputs.begin(), m_nInputs);
-}
-
-class Node::Uses::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = int;
- using value_type = Node *;
- using pointer = Node **;
- using reference = Node *&;
-
- Node *operator*() const
- { return m_current->user(); }
-
- bool operator==(const const_iterator &other) const
- { return other.m_current == m_current; }
-
- bool operator!=(const const_iterator &other) const
- { return other.m_current != m_current; }
-
- const_iterator &operator++()
- { m_current = m_next; setNext(); return *this; }
-
- unsigned inputIndex() const
- { return m_current->inputIndex(); }
-
- bool isUsedAsValue() const
- { return inputIndex() < operator*()->operation()->valueInputCount(); }
-
- bool isUsedAsControl() const
- { return operator*()->operation()->indexOfFirstControl() <= inputIndex(); }
-
-private:
- friend class Node::Uses;
-
- const_iterator() = default;
-
- explicit const_iterator(Node* node)
- : m_current(node->m_firstUse)
- { setNext(); }
-
- void setNext()
- {
- if (m_current)
- m_next = m_current->m_next;
- else
- m_next = nullptr;
- }
-
-private:
- Use *m_current = nullptr;
- Use *m_next = nullptr;
-};
-
-Node::Uses::const_iterator Node::Uses::begin() const
-{ return const_iterator(this->m_node); }
-
-Node::Uses::const_iterator Node::Uses::end() const
-{ return const_iterator(); }
-
-int Use::inputIndex() const
-{
- if (!m_user)
- return -1;
- return int(this - m_user->m_inputs.begin());
-}
-
-bool Node::isDead() const
-{
- Inputs in = inputs();
- return !in.empty() && *in.begin() == nullptr;
-}
-
-void Node::kill()
-{
- removeAllInputs();
-}
-
-class NodeWorkList final
-{
- enum State: uint8_t {
- Unvisited = 0,
- Queued,
- Visited,
- };
-
-public:
- NodeWorkList(const Graph *g);
-
- void reset();
-
- bool enqueue(Node *n)
- {
- State &s = nodeState(n);
- if (s == Queued || s == Visited)
- return false;
-
- m_worklist.push_back(n);
- s = Queued;
- return true;
- }
-
- void enqueue(const std::vector<Node *> &nodes)
- {
- m_worklist.insert(m_worklist.end(), nodes.begin(), nodes.end());
- for (Node *n : nodes)
- nodeState(n) = Queued;
- }
-
- void reEnqueue(Node *n)
- {
- if (!n)
- return;
- State &s = nodeState(n);
- if (s == Queued)
- return;
- s = Queued;
- m_worklist.push_back(n);
- }
-
- void enqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- enqueue(input);
- }
-
- void reEnqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- reEnqueue(input);
- }
-
- void enqueueValueInputs(Node *n)
- {
- for (unsigned i = 0, ei = n->operation()->valueInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueEffectInputs(Node *n)
- {
- for (unsigned i = n->operation()->indexOfFirstEffect(), ei = n->operation()->effectInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueAllUses(Node *n)
- {
- for (Node *use : n->uses())
- enqueue(use);
- }
-
- Node *dequeueNextNodeForVisiting()
- {
- while (!m_worklist.empty()) {
- Node *n = m_worklist.back();
- m_worklist.pop_back();
- State &s = nodeState(n);
- Q_ASSERT(s == Queued);
- s = Visited;
- return n;
- }
-
- return nullptr;
- }
-
- bool isVisited(Node *n) const
- { return nodeState(n) == Visited; }
-
- bool isEmpty() const
- { return m_worklist.empty(); }
-
- QString status(Node *n) const
- {
- QString s = QStringLiteral("status for node %1: ").arg(n->id());
- switch (nodeState(n)) {
- case Queued: s += QLatin1String("queued"); break;
- case Visited: s += QLatin1String("visited"); break;
- case Unvisited: s += QLatin1String("unvisited"); break;
- }
- return s;
- }
-
-private:
- State &nodeState(Node *n)
- {
- const unsigned position(n->id());
- if (position >= m_nodeState.size())
- m_nodeState.resize(position + 1, Unvisited);
-
- return m_nodeState[position];
- }
-
- State nodeState(Node *n) const
- { return m_nodeState[unsigned(n->id())]; }
-
-private:
- std::vector<Node *> m_worklist;
- std::vector<State> m_nodeState;
-};
-
-class NodeInfo
-{
-public:
- enum { NoInstructionOffset = -1 };
-
-public:
- NodeInfo() = default;
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- int currentInstructionOffset() const
- { return m_currentInstructionOffset; }
-
- int nextInstructionOffset() const
- { return m_nextInstructionOffset; }
-
- void setBytecodeOffsets(int current, int next)
- {
- Q_ASSERT(current != NoInstructionOffset);
- Q_ASSERT(next != NoInstructionOffset);
- m_currentInstructionOffset = current;
- m_nextInstructionOffset = next;
- }
-
-private:
- Type m_type;
- int m_currentInstructionOffset = NoInstructionOffset;
- int m_nextInstructionOffset = NoInstructionOffset;
-};
-
-class NodeCollector
-{
-public:
- NodeCollector(const Graph *g, bool collectUses = false, bool skipFramestate = false);
-
- const std::vector<Node *> &reachable() const
- { return m_reachable; }
-
- void sortById()
- {
- std::sort(m_reachable.begin(), m_reachable.end(), [](Node *n1, Node *n2) {
- return n1->id() < n2->id();
- });
- }
-
- bool isReachable(Node::Id nodeId) const
- {
- if (nodeId >= Node::Id(m_isReachable.size()))
- return false;
- return m_isReachable.at(int(nodeId));
- }
-
- void markReachable(Node *node)
- {
- auto nodeId = node->id();
- m_reachable.push_back(node);
- if (nodeId >= Node::Id(m_isReachable.size()))
- m_isReachable.resize(int(nodeId + 1), false);
- m_isReachable.setBit(int(nodeId));
- }
-
-private:
- std::vector<Node *> m_reachable;
- BitVector m_isReachable;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4NODE_P_H
diff --git a/src/qml/jit/qv4operation.cpp b/src/qml/jit/qv4operation.cpp
deleted file mode 100644
index acd5328fd0..0000000000
--- a/src/qml/jit/qv4operation.cpp
+++ /dev/null
@@ -1,770 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4operation_p.h"
-#include "qv4runtimesupport_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-OperationBuilder::OperationBuilder(QQmlJS::MemoryPool *graphPool)
- : m_graphPool(graphPool)
-{}
-
-OperationBuilder *OperationBuilder::create(QQmlJS::MemoryPool *pool)
-{
- return pool->New<OperationBuilder>(pool);
-}
-
-Operation *OperationBuilder::getConstant(Value v)
-{
- Type t;
- switch (v.type()) {
- case Value::Undefined_Type: t = Type::undefinedType(); break;
- case Value::Integer_Type: t = Type::int32Type(); break;
- case Value::Boolean_Type: t = Type::booleanType(); break;
- case Value::Null_Type: t = Type::nullType(); break;
- case Value::Double_Type: t = Type::doubleType(); break;
- case Value::Managed_Type: t = Type::objectType(); break;
- default:
- if (v.isEmpty())
- t = Type::emptyType();
- else
- Q_UNREACHABLE();
- }
- return OperationWithPayload<ConstantPayload>::create(
- m_graphPool, Meta::Constant, 0, 0, 0, 1, 0, 0, t, Operation::NoFlags,
- ConstantPayload(v));
-}
-
-Operation *OperationBuilder::getParam(unsigned index, const Function::StringId name)
-{
- return OperationWithPayload<ParameterPayload>::create(m_graphPool, Meta::Parameter,
- 1, 0, 0,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags,
- ParameterPayload(index, name));
-}
-
-Operation *OperationBuilder::getRegion(unsigned nControlInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Region,
- 0, 0, uint16_t(nControlInputs),
- 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getPhi(unsigned nValueInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Phi,
- uint16_t(nValueInputs), 0, 1,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEffectPhi(unsigned nEffectInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::EffectPhi,
- 0, uint16_t(nEffectInputs), 1,
- 0, 1, 0,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getUnwindDispatch(unsigned nContinuations, int unwindHandlerOffset,
- int fallthroughSuccessor)
-{
- return OperationWithPayload<UnwindDispatchPayload>::create(
- m_graphPool, Meta::UnwindDispatch,
- 0, 1, 1, 0, nContinuations, nContinuations,
- Type(), Operation::NoFlags,
- UnwindDispatchPayload(unwindHandlerOffset,
- fallthroughSuccessor));
-}
-
-Operation *OperationBuilder::getHandleUnwind(int unwindHandlerOffset)
-{
- return OperationWithPayload<HandleUnwindPayload>::create(m_graphPool, Meta::HandleUnwind,
- 0, 1, 1, 0, 1, 1,
- Type(), Operation::NoFlags,
- HandleUnwindPayload(unwindHandlerOffset));
-}
-
-Operation *OperationBuilder::getFrameState(uint16_t frameSize)
-{
- if (m_opFrameState == nullptr)
- m_opFrameState = Operation::create(m_graphPool, Meta::FrameState,
- frameSize, 0, 0, 0, 0, 1,
- Type(), Operation::NoFlags);
- else
- Q_ASSERT(frameSize == m_opFrameState->valueInputCount());
-
- return m_opFrameState;
-}
-
-Operation *OperationBuilder::getStart(uint16_t outputCount)
-{
- return Operation::create(m_graphPool, Meta::Start,
- 0, 0, 0,
- outputCount, 1, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEnd(uint16_t controlInputCount)
-{
- return Operation::create(m_graphPool, Meta::End,
- 0, 0, controlInputCount,
- 0, 0, 0,
- Type(), Operation::NoFlags);
-}
-
-inline Operation *createOperation(Operation::Kind kind, QQmlJS::MemoryPool *staticPool)
-{
- auto get = [&](uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type (*typeCreator)(), uint8_t flags) {
- return Operation::create(staticPool, kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount, typeCreator(),
- flags);
- };
-
- using K = Operation::Kind;
- using F = Operation::Flags;
- const auto none = &Type::noneType;
- const auto any = &Type::anyType;
- const auto number = &Type::numberType;
- const auto boolean = &Type::booleanType;
-
- switch (kind) {
- case K::Undefined:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Undefined, 0, 0, 0, 1, 0, 0, Type::undefinedType(), F::NoFlags,
- ConstantPayload(Primitive::undefinedValue()));
- case K::Empty:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Constant, 0, 0, 0, 1, 0, 0, Type::emptyType(), Operation::NoFlags,
- ConstantPayload(Primitive::emptyValue()));
- case K::Engine: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::CppFrame: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Function: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Jump: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::Return: return get(1, 1, 1, 0, 0, 1, none, F::NoFlags);
- case K::Branch: return get(1, 0, 1, 0, 0, 2, none, F::HasFrameStateInput | F::NeedsBytecodeOffsets);
- case K::IfTrue: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::IfFalse: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::SelectOutput: return get(3, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::Throw: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::OnException: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::ThrowReferenceError: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::UnwindToLabel: return get(2, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::LoadRegExp: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::ScopedLoad: return get(2, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::ScopedStore: return get(3, 1, 0, 0, 1, 0, none, F::NoFlags);
- case K::JSLoadElement: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSGetLookup: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreElement: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupStrict: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupSloppy: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreProperty: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadGlobalLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreNameSloppy: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreNameStrict: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadSuperProperty: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreSuperProperty: return get(2, 1, 1, 0, 1, 2, any, F::CanThrow);
- case K::JSLoadClosure: return get(1, 1, 0, 1, 1, 0, any, F::Pure);
- case K::JSGetIterator: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNext: return get(2, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNextForYieldStar: return get(3, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- case K::JSIteratorClose: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSIn: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSInstanceOf: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::QMLLoadQmlContextPropertyLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSStrictEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
-
- case K::JSAdd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSSubtract: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSMultiply: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSDivide: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSModulo: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSExponentiate: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
-
- case K::JSBitAnd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitOr: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitXor: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSUnsignedShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftLeft: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSNegate: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSToNumber: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::Alloca: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- //### it is questionable if VAAlloc/VASeal need effect edges
- case K::VAAlloc: return get(1, 1, 0, 1, 1, 0, none, F::NoFlags);
-
- case K::VAStore: return get(3, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- case K::JSTypeofName: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSTypeofValue: return get(1, 0, 0, 1, 0, 0, any, F::Pure);
- case K::JSDeclareVar: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDestructureRestElement: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSCreateCallContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateCatchContext: return get(2, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCreateWithContext: return get(1, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::JSCreateBlockContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCloneBlockContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateScriptContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSPopScriptContext: return get(0, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::PopContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
-
- case K::JSThisToObject: return get(1, 1, 1, 0, 1, 2, any, F::NoFlags);
- case K::JSCreateMappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateUnmappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateRestParameter: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::JSLoadSuperConstructor: return get(1, 1, 1, 1, 1, 2, any, F::NoFlags);
- case K::JSThrowOnNullOrUndefined: return get(1, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSGetTemplateObject: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::StoreThis: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
-
- case K::GetException: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::SetException: return get(1, 1, 0, 0, 1, 0, any, F::NoFlags);
-
- case K::ToObject: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::ToBoolean: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::IsEmpty: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::BooleanNot: return get(1, 0, 0, 1, 0, 0, boolean, F::NoFlags);
- case K::HasException: return get(1, 1, 0, 1, 1, 0, boolean, F::NoFlags);
-
- case K::Swap: return get(0, 0, 0, 0, 0, 0, none, F::NoFlags);
- case K::Move: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- default: // Non-static operations:
- return nullptr;
- }
-}
-
-Operation *OperationBuilder::staticOperation(Operation::Kind kind)
-{
- static QAtomicPointer<Operation *> ops;
- if (Operation **staticOps = ops.load())
- return staticOps[kind];
-
- static QAtomicInt initializing = 0;
- if (initializing.testAndSetOrdered(0, 1)) {
- // This is safe now, because we can only run this piece of code once during the life time
- // of the application as we can only change initializing from 0 to 1 once.
- Operation **staticOps = new Operation *[Meta::KindsEnd];
- static QQmlJS::MemoryPool pool;
- for (int i = 0; i < Meta::KindsEnd; ++i)
- staticOps[i] = createOperation(Operation::Kind(i), &pool);
- bool success = ops.testAndSetOrdered(nullptr, staticOps);
- Q_ASSERT(success);
- } else {
- // Unfortunately we need to busy wait now until the other thread finishes the static
- // initialization;
- while (!ops.load()) {}
- }
-
- return ops.load()[kind];
-}
-
-Operation *OperationBuilder::getJSVarArgsCall(Operation::Kind kind, uint16_t argc)
-{
- return Operation::create(m_graphPool, kind,
- argc, 1, 1, 1, 1, 2,
- Type::anyType(), Operation::CanThrow);
-}
-
-Operation *OperationBuilder::getJSTailCall(uint16_t argc)
-{
- return Operation::create(m_graphPool, Meta::JSTailCall,
- argc, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getTailCall()
-{
- // special varargs call, takes cppframe, engine, func, thisObject, argv, argc
- return Operation::create(m_graphPool, Meta::TailCall,
- 6, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getCall(Operation::Kind callee)
-{
- const bool canThrow = CallPayload::canThrow(callee);
- const Type retTy = CallPayload::returnType(callee);
- uint16_t nControlInputs = 0;
- uint16_t nControlOutputs = 0;
- if (canThrow) {
- nControlInputs = 1;
- nControlOutputs += 2;
- }
- if (CallPayload::changesContext(callee)) {
- nControlInputs = 1;
- nControlOutputs = std::max<uint16_t>(nControlInputs, 1);
- }
- if (callee == Meta::Throw || callee == Meta::ThrowReferenceError ||
- callee == Meta::JSIteratorNext || callee == Meta::JSIteratorNextForYieldStar) {
- nControlInputs = 1;
- nControlOutputs = 1;
- }
- Operation::Flags flags = Operation::NoFlags;
- if (canThrow)
- flags = Operation::Flags(flags | Operation::CanThrow);
- if (CallPayload::isPure(callee))
- flags = Operation::Flags(flags | Operation::Pure);
- const uint16_t nEffects = (flags & Operation::Pure) ? 0 : 1;
- const uint16_t nValueOutputs = retTy.isNone() ? 0 : 1;
- const uint16_t nValueInputs = CallPayload::argc(callee);
-
- return OperationWithPayload<CallPayload>::create(
- m_graphPool, Meta::Call,
- nValueInputs, nEffects, nControlInputs,
- nValueOutputs, nEffects, nControlOutputs,
- retTy, flags,
- CallPayload(callee));
-}
-
-Operation *OperationBuilder::getVASeal(uint16_t nElements)
-{
- return Operation::create(m_graphPool, Meta::VASeal,
- nElements + 1, 1, 0, 1, 1, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-QString Operation::debugString() const
-{
- switch (kind()) {
-
- case Meta::Constant:
- return QStringLiteral("Constant[%1]").arg(ConstantPayload::get(*this)->debugString());
- case Meta::Parameter:
- return QStringLiteral("Parameter[%1]").arg(ParameterPayload::get(*this)->debugString());
- case Meta::Call:
- return QStringLiteral("Call[%1]").arg(CallPayload::get(*this)->debugString());
- case Meta::UnwindDispatch:
- return QStringLiteral("UnwindDispatch[%1]").arg(UnwindDispatchPayload::get(*this)
- ->debugString());
- case Meta::HandleUnwind:
- return QStringLiteral("HandleUnwind[%1]").arg(HandleUnwindPayload::get(*this)
- ->debugString());
-
- default:
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(kind()));
- }
-}
-
-QString ConstantPayload::debugString() const
-{
- return debugString(m_value);
-}
-
-QString ConstantPayload::debugString(QV4::Value v)
-{
- if (v.isManaged())
- return QString::asprintf("Ptr: %p", v.heapObject());
- if (v.isEmpty())
- return QStringLiteral("empty");
- return v.toQStringNoThrow();
-}
-
-QString ParameterPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_index);
-}
-
-QString UnwindDispatchPayload::debugString() const
-{
- return QStringLiteral("%1, %2").arg(QString::number(m_fallthroughSuccessor),
- QString::number(m_unwindHandlerOffset));
-}
-
-QString HandleUnwindPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_unwindHandlerOffset);
-}
-
-static Type translateType(RuntimeSupport::ArgumentType t)
-{
- switch (t) {
- case RuntimeSupport::ArgumentType::Int: return Type::int32Type();
- case RuntimeSupport::ArgumentType::Bool: return Type::booleanType();
- case RuntimeSupport::ArgumentType::Void: return Type();
- case RuntimeSupport::ArgumentType::Engine: return Type::rawPointerType();
- case RuntimeSupport::ArgumentType::ValueRef: return Type::anyType();
- case RuntimeSupport::ArgumentType::ValueArray: return Type::anyType();
- case RuntimeSupport::ArgumentType::ReturnedValue: return Type::anyType();
- default: Q_UNREACHABLE();
- }
-}
-
-template<template<typename Operation> class M /* MetaOperation */, typename ReturnValue>
-static ReturnValue operateOnRuntimeCall(Operation::Kind kind, bool abortOnMissingCall = true)
-{
- using K = Operation::Kind;
- using R = Runtime;
-
- switch (kind) {
- case K::Throw: return M<R::ThrowException>::doIt();
- case K::ThrowReferenceError: return M<R::ThrowReferenceError>::doIt();
-
- case K::JSEqual: return M<R::CompareEqual>::doIt();
- case K::JSGreaterThan: return M<R::CompareGreaterThan>::doIt();
- case K::JSGreaterEqual: return M<R::CompareGreaterEqual>::doIt();
- case K::JSLessThan: return M<R::CompareLessThan>::doIt();
- case K::JSLessEqual: return M<R::CompareLessEqual>::doIt();
- case K::JSStrictEqual: return M<R::CompareStrictEqual>::doIt();
-
- case K::JSBitAnd: return M<R::BitAnd>::doIt();
- case K::JSBitOr: return M<R::BitOr>::doIt();
- case K::JSBitXor: return M<R::BitXor>::doIt();
- case K::JSUnsignedShiftRight: return M<R::UShr>::doIt();
- case K::JSShiftRight: return M<R::Shr>::doIt();
- case K::JSShiftLeft: return M<R::Shl>::doIt();
-
- case K::JSAdd: return M<R::Add>::doIt();
- case K::JSSubtract: return M<R::Sub>::doIt();
- case K::JSMultiply: return M<R::Mul>::doIt();
- case K::JSDivide: return M<R::Div>::doIt();
- case K::JSModulo: return M<R::Mod>::doIt();
- case K::JSExponentiate: return M<R::Exp>::doIt();
-
- case K::ToBoolean: return M<R::ToBoolean>::doIt();
- case K::ToObject: return M<R::ToObject>::doIt();
-
- case K::JSNegate: return M<R::UMinus>::doIt();
- case K::JSToNumber: return M<R::ToNumber>::doIt();
-
- case K::JSLoadName: return M<R::LoadName>::doIt();
- case K::JSLoadElement: return M<R::LoadElement>::doIt();
- case K::JSStoreElement: return M<R::StoreElement>::doIt();
- case K::JSGetLookup: return M<R::GetLookup>::doIt();
- case K::JSSetLookupStrict: return M<R::SetLookupStrict>::doIt();
- case K::JSSetLookupSloppy: return M<R::SetLookupSloppy>::doIt();
- case K::JSLoadProperty: return M<R::LoadProperty>::doIt();
- case K::JSStoreProperty: return M<R::StoreProperty>::doIt();
- case K::JSLoadGlobalLookup: return M<R::LoadGlobalLookup>::doIt();
- case K::JSStoreNameSloppy: return M<R::StoreNameSloppy>::doIt();
- case K::JSStoreNameStrict: return M<R::StoreNameStrict>::doIt();
- case K::JSLoadSuperProperty: return M<R::LoadSuperProperty>::doIt();
- case K::JSStoreSuperProperty: return M<R::StoreSuperProperty>::doIt();
- case K::JSLoadClosure: return M<R::Closure>::doIt();
- case K::JSGetIterator: return M<R::GetIterator>::doIt();
- case K::JSIteratorNext: return M<R::IteratorNext>::doIt();
- case K::JSIteratorNextForYieldStar: return M<R::IteratorNextForYieldStar>::doIt();
- case K::JSIteratorClose: return M<R::IteratorClose>::doIt();
- case K::JSDeleteProperty: return M<R::DeleteProperty>::doIt();
- case K::JSDeleteName: return M<R::DeleteName>::doIt();
- case K::JSIn: return M<R::In>::doIt();
- case K::JSInstanceOf: return M<R::Instanceof>::doIt();
- case K::QMLLoadQmlContextPropertyLookup: return M<R::LoadQmlContextPropertyLookup>::doIt();
-
- case K::JSTypeofName: return M<R::TypeofName>::doIt();
- case K::JSTypeofValue: return M<R::TypeofValue>::doIt();
- case K::JSDeclareVar: return M<R::DeclareVar>::doIt();
- case K::JSDestructureRestElement: return M<R::DestructureRestElement>::doIt();
- case K::JSThisToObject: return M<R::ConvertThisToObject>::doIt();
- case K::JSCreateMappedArgumentsObject: return M<R::CreateMappedArgumentsObject>::doIt();
- case K::JSCreateUnmappedArgumentsObject: return M<R::CreateUnmappedArgumentsObject>::doIt();
- case K::JSCreateRestParameter: return M<R::CreateRestParameter>::doIt();
- case K::JSLoadSuperConstructor: return M<R::LoadSuperConstructor>::doIt();
- case K::JSThrowOnNullOrUndefined: return M<R::ThrowOnNullOrUndefined>::doIt();
-
- case K::JSCreateCallContext: return M<R::PushCallContext>::doIt();
- case K::JSCreateCatchContext: return M<R::PushCatchContext>::doIt();
- case K::JSCreateWithContext: return M<R::PushWithContext>::doIt();
- case K::JSCreateBlockContext: return M<R::PushBlockContext>::doIt();
- case K::JSCloneBlockContext: return M<R::CloneBlockContext>::doIt();
- case K::JSCreateScriptContext: return M<R::PushScriptContext>::doIt();
- case K::JSPopScriptContext: return M<R::PopScriptContext>::doIt();
-
- case K::LoadRegExp: return M<R::RegexpLiteral>::doIt();
- case K::JSGetTemplateObject: return M<R::GetTemplateObject>::doIt();
-
- case K::JSCallName: return M<R::CallName>::doIt();
- case K::JSCallValue: return M<R::CallValue>::doIt();
- case K::JSCallElement: return M<R::CallElement>::doIt();
- case K::JSCallLookup: return M<R::CallPropertyLookup>::doIt();
- case K::JSCallProperty: return M<R::CallProperty>::doIt();
- case K::JSCallGlobalLookup: return M<R::CallGlobalLookup>::doIt();
- case K::JSCallPossiblyDirectEval: return M<R::CallPossiblyDirectEval>::doIt();
- case K::JSCallWithReceiver: return M<R::CallWithReceiver>::doIt();
- case K::JSDefineObjectLiteral: return M<R::ObjectLiteral>::doIt();
- case K::JSDefineArray: return M<R::ArrayLiteral>::doIt();
- case K::JSCallWithSpread: return M<R::CallWithSpread>::doIt();
- case K::JSConstruct: return M<R::Construct>::doIt();
- case K::JSConstructWithSpread: return M<R::ConstructWithSpread>::doIt();
- case K::JSTailCall: return M<R::TailCall>::doIt();
- case K::JSCreateClass: return M<R::CreateClass>::doIt();
- default:
- if (abortOnMissingCall)
- Q_UNREACHABLE();
- else
- return ReturnValue();
- }
-}
-
-template<typename Method>
-struct IsRuntimeMethodOperation
-{
- static constexpr bool doIt() { return true; }
-};
-
-bool CallPayload::isRuntimeCall(Operation::Kind m)
-{
- return operateOnRuntimeCall<IsRuntimeMethodOperation, bool>(m, false);
-}
-
-QString CallPayload::debugString() const
-{
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(m_callee));
-}
-
-template<typename Method>
-struct MethodArgcOperation
-{
- static constexpr unsigned doIt() { return RuntimeSupport::argumentCount<Method>(); }
-};
-
-unsigned CallPayload::argc(Operation::Kind callee)
-{
- return operateOnRuntimeCall<MethodArgcOperation, unsigned>(callee);
-}
-
-template<typename Method> struct MethodArg1TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg1Type<Method>(); } };
-template<typename Method> struct MethodArg2TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg2Type<Method>(); } };
-template<typename Method> struct MethodArg3TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg3Type<Method>(); } };
-template<typename Method> struct MethodArg4TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg4Type<Method>(); } };
-template<typename Method> struct MethodArg5TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg5Type<Method>(); } };
-template<typename Method> struct MethodArg6TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg6Type<Method>(); } };
-
-static RuntimeSupport::ArgumentType untranslatedArgumentType(Operation::Kind m, unsigned arg)
-{
- if (m == Meta::JSTailCall) {
- if (arg < 4)
- return RuntimeSupport::ArgumentType::ValueRef;
- else
- return RuntimeSupport::ArgumentType::Invalid;
- }
-
- switch (arg) {
- case 0: return operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m);
- case 1: return operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m);
- case 2: return operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m);
- case 3: return operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m);
- case 4: return operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m);
- case 5: return operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m);
- default: return RuntimeSupport::ArgumentType::Invalid;
- }
-}
-
-bool CallPayload::needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType)
-{
- auto argTy = untranslatedArgumentType(m, arg);
- if (argTy == RuntimeSupport::ArgumentType::ValueArray)
- return true;
- if (argTy != RuntimeSupport::ArgumentType::ValueRef)
- return false;
-
- if (op->kind() == Meta::Constant)
- return true;
-
- return !nodeType.isObject() && !nodeType.isRawPointer() && !nodeType.isAny();
-}
-
-template<typename Method>
-struct MethodRetTyOperation
-{
- static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::retType<Method>(); }
-};
-
-Type CallPayload::returnType(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return Type();
-
- auto t = operateOnRuntimeCall<MethodRetTyOperation, RuntimeSupport::ArgumentType>(m);
- return translateType(t);
-}
-
-static int firstArgumentPositionForType(Operation::Kind m, RuntimeSupport::ArgumentType type)
-{
- if (operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 1;
- if (operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 2;
- if (operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 3;
- if (operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 4;
- if (operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 5;
- if (operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 6;
- return -1;
-}
-
-unsigned CallPayload::varArgsStart(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return 4 - 1;
-
- int pos = firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) - 1;
- Q_ASSERT(pos >= 0);
- return pos;
-}
-
-bool CallPayload::isVarArgsCall(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return true;
- if (lastArgumentIsOutputValue(m))
- return false;
- return firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) != -1;
-}
-
-bool CallPayload::isVarArgsCall() const
-{
- return isVarArgsCall(m_callee);
-}
-
-template<typename Method>
-struct MethodsLastArgumentIsOutputValue
-{
- static constexpr bool doIt() { return Method::lastArgumentIsOutputValue; }
-};
-
-bool CallPayload::lastArgumentIsOutputValue(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodsLastArgumentIsOutputValue, bool>(m);
-}
-
-template<typename Method>
-struct MethodChangesContext
-{
- static constexpr bool doIt() { return Method::changesContext; }
-};
-
-bool CallPayload::changesContext(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodChangesContext, bool>(m);
-}
-
-template<typename Method>
-struct MethodIsPure
-{
- static constexpr bool doIt() { return Method::pure; }
-};
-
-bool CallPayload::isPure(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodIsPure, bool>(m);
-}
-
-template<typename Method>
-struct MethodCanThrow
-{
- static constexpr bool doIt() { return Method::throws; }
-};
-
-bool CallPayload::canThrow(Operation::Kind m)
-{
- switch (m) {
- case Meta::Throw: Q_FALLTHROUGH();
- case Meta::ThrowReferenceError:
- // the execution path following these instructions is already linked up to the exception handler
- return false;
- case Meta::JSIteratorNext: Q_FALLTHROUGH();
- case Meta::JSIteratorNextForYieldStar:
- // special case: see GraphBuilder::generate_IteratorNext
- return false;
- default:
- return operateOnRuntimeCall<MethodCanThrow, bool>(m);
- }
-}
-
-bool CallPayload::takesEngineAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Engine;
-}
-
-bool CallPayload::takesFunctionAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Function;
-}
-
-bool CallPayload::takesFrameAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Frame;
-}
-
-template<typename Method>
-struct GetMethodPtr
-{
- static constexpr void *doIt() { return reinterpret_cast<void *>(&Method::call); }
-};
-
-void *CallPayload::getMethodPtr(Operation::Kind m)
-{
- return operateOnRuntimeCall<GetMethodPtr, void *>(m);
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4operation_p.h b/src/qml/jit/qv4operation_p.h
deleted file mode 100644
index 43214023e8..0000000000
--- a/src/qml/jit/qv4operation_p.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4OPERATION_P_H
-#define QV4OPERATION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4ir_p.h>
-#include <private/qqmljsmemorypool_p.h>
-
-#include <QtCore/qatomic.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-namespace Meta {
-enum OpKind: uint16_t {
- FrameState,
- Start,
- End,
-
- Undefined,
- Constant,
- Parameter,
- Empty,
- Engine,
- CppFrame,
- Function,
-
- Jump,
- Return,
- JSTailCall,
- TailCall,
- Branch,
- IfTrue,
- IfFalse,
- Region,
- OnException,
- Phi,
- EffectPhi,
- SelectOutput,
- UnwindDispatch,
- UnwindToLabel,
- HandleUnwind,
- Throw,
- ThrowReferenceError,
-
- Call,
-
- LoadRegExp,
- ScopedLoad,
- ScopedStore,
-
- JSLoadElement,
- JSStoreElement,
- JSGetLookup,
- JSSetLookupStrict,
- JSSetLookupSloppy,
- JSLoadProperty,
- JSStoreProperty,
- JSLoadName,
- JSLoadGlobalLookup,
- JSStoreNameSloppy,
- JSStoreNameStrict,
- JSLoadSuperProperty,
- JSStoreSuperProperty,
- JSLoadClosure,
- JSGetIterator,
- JSIteratorNext,
- JSIteratorNextForYieldStar,
- JSIteratorClose,
- JSDeleteProperty,
- JSDeleteName,
- JSIn,
- JSInstanceOf,
-
- /* ok, these are qml object ops, but we don't care for now and treat them as JS */
- QMLLoadQmlContextPropertyLookup,
- QMLCallQmlContextPropertyLookup,
-
- JSEqual,
- JSGreaterThan,
- JSGreaterEqual,
- JSLessThan,
- JSLessEqual,
- JSStrictEqual,
-
- JSAdd,
- JSSubtract,
- JSMultiply,
- JSDivide,
- JSModulo,
- JSExponentiate,
-
- JSBitAnd,
- JSBitOr,
- JSBitXor,
- JSUnsignedShiftRight,
- JSShiftRight,
- JSShiftLeft,
-
- JSNegate,
- JSToNumber,
-
- JSCallName,
- JSCallValue,
- JSCallElement,
- JSCallProperty,
- JSCallLookup,
- JSCallGlobalLookup,
- JSCallPossiblyDirectEval,
- JSCallWithReceiver,
- JSCallWithSpread,
- JSDefineObjectLiteral,
- JSDefineArray,
- JSCreateClass,
- JSConstruct,
- JSConstructWithSpread,
-
- JSTypeofName,
- JSTypeofValue,
- JSDeclareVar,
- JSDestructureRestElement,
- JSThisToObject,
- JSCreateMappedArgumentsObject,
- JSCreateUnmappedArgumentsObject,
- JSCreateRestParameter,
- JSLoadSuperConstructor,
- JSThrowOnNullOrUndefined,
- JSGetTemplateObject,
- StoreThis,
-
- JSCreateCallContext,
- JSCreateCatchContext,
- JSCreateWithContext,
- JSCreateBlockContext,
- JSCloneBlockContext,
- JSCreateScriptContext,
- JSPopScriptContext,
- PopContext,
-
- GetException,
- SetException,
-
- ToObject,
- ToBoolean,
-
- //### do we need this? Or should a later phase generate JumpIsEmpty?
- IsEmpty,
-
- Alloca,
- VAAlloc,
- VAStore,
- VASeal,
-
- BooleanNot,
- HasException,
-
- // Low level, used by the register allocator and stack allocator:
- Swap,
- Move,
- KindsEnd
-};
-Q_NAMESPACE
-Q_ENUM_NS(OpKind)
-} // namespace Ops
-
-class Operation
-{
- Q_DISABLE_COPY_MOVE(Operation)
-
-public:
- using Kind = Meta::OpKind;
-
- enum Flags: uint8_t {
- NoFlags = 0,
- ThrowsFlag = 1 << 0,
- Pure = 1 << 1, // no read/write side effect, cannot throw, cannot deopt, and is idempotent
- NeedsBytecodeOffsets = 1 << 2,
-
- CanThrow = ThrowsFlag | NeedsBytecodeOffsets,
-
- HasFrameStateInput = 1 << 3,
- };
-
-public:
- static Operation *create(QQmlJS::MemoryPool *pool, Kind kind, uint16_t inValueCount,
- uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount,
- uint16_t outControlCount, Type type, uint8_t flags)
- {
- return pool->New<Operation>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, Flags(flags));
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isConstant() const
- {
- switch (kind()) {
- case Meta::Undefined: Q_FALLTHROUGH();
- case Meta::Constant:
- case Meta::Empty:
- return true;
- default:
- return false;
- }
- }
-
- QString debugString() const;
-
- uint16_t valueInputCount() const { return m_inValueCount; }
- uint16_t effectInputCount() const { return m_inEffectCount; }
- uint16_t controlInputCount() const { return m_inControlCount; }
- uint16_t valueOutputCount() const { return m_outValueCount; }
- uint16_t effectOutputCount() const { return m_outEffectCount; }
- uint16_t controlOutputCount() const { return m_outControlCount; }
-
- unsigned indexOfFirstEffect() const { return m_inValueCount; }
- unsigned indexOfFirstControl() const { return m_inValueCount + m_inEffectCount; }
- unsigned indexOfFrameStateInput() const
- {
- return hasFrameStateInput() ? indexOfFirstControl() + m_inControlCount
- : std::numeric_limits<unsigned>::max();
- }
-
- Type type() const
- { return m_type; }
-
- bool canThrow() const
- { return m_flags & ThrowsFlag; }
-
- bool isPure() const
- { return m_flags & Pure; }
-
- bool needsBytecodeOffsets() const
- { return m_flags & NeedsBytecodeOffsets; }
-
- bool hasFrameStateInput() const
- { return m_flags & HasFrameStateInput; }
-
- unsigned totalInputCount() const
- {
- return valueInputCount() + effectInputCount() + controlInputCount() +
- (hasFrameStateInput() ? 1 : 0);
- }
- unsigned totalOutputCount() const { return valueOutputCount() + effectOutputCount() + controlOutputCount(); }
-
-protected:
- friend class QQmlJS::MemoryPool;
- Operation(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, uint8_t flags)
- : m_kind(kind)
- , m_inValueCount(inValueCount)
- , m_inEffectCount(inEffectCount)
- , m_inControlCount(inControlCount)
- , m_outValueCount(outValueCount)
- , m_outEffectCount(outEffectCount)
- , m_outControlCount(outControlCount)
- , m_type(type)
- , m_flags(Flags(flags))
- {
- }
-
- ~Operation() = default;
-
-private:
- Kind m_kind;
- uint16_t m_inValueCount;
- uint16_t m_inEffectCount;
- uint16_t m_inControlCount;
- uint16_t m_outValueCount;
- uint16_t m_outEffectCount;
- uint16_t m_outControlCount;
- Type m_type;
- Flags m_flags;
-};
-
-template <typename Payload>
-class OperationWithPayload: public Operation
-{
-public:
- static OperationWithPayload *create(QQmlJS::MemoryPool *pool, Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- {
- return pool->New<OperationWithPayload>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags, payload);
- }
-
- const Payload &payload() const
- { return m_payload; }
-
-protected:
- friend class QQmlJS::MemoryPool;
- OperationWithPayload(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- : Operation(kind,
- inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags)
- , m_payload(payload)
- {}
-
- ~OperationWithPayload() = default;
-
-private:
- Payload m_payload;
-};
-
-class ConstantPayload
-{
-public:
- explicit ConstantPayload(QV4::Value v)
- : m_value(v)
- {}
-
- QV4::Value value() const
- { return m_value; }
-
- static const ConstantPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Constant)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ConstantPayload>&>(op).payload();
- }
-
- QString debugString() const;
- static QString debugString(QV4::Value v);
-
-private:
- QV4::Value m_value;
-};
-
-class ParameterPayload
-{
-public:
- ParameterPayload(size_t index, Function::StringId stringId)
- : m_index(index)
- , m_stringId(stringId)
- {}
-
- size_t parameterIndex() const
- { return m_index; }
-
- Function::StringId stringId() const
- { return m_stringId; }
-
- static const ParameterPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Parameter)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ParameterPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- size_t m_index;
- Function::StringId m_stringId;
-};
-
-class CallPayload
-{
-public:
- CallPayload(Operation::Kind callee)
- : m_callee(callee)
- {}
-
- static const CallPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Call)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<CallPayload>&>(op).payload();
- }
-
- static bool isRuntimeCall(Operation::Kind m);
-
- Operation::Kind callee() const { return m_callee; }
- QString debugString() const;
-
- unsigned argc() const { return argc(m_callee); }
- static unsigned argc(Operation::Kind callee);
- static bool needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType);
- static Type returnType(Operation::Kind m);
- static int engineArgumentPosition(Operation::Kind m);
- static int functionArgumentPosition(Operation::Kind m);
-
- static constexpr unsigned NoVarArgs = std::numeric_limits<unsigned>::max();
- static unsigned varArgsStart(Operation::Kind m);
- static bool isVarArgsCall(Operation::Kind m);
- bool isVarArgsCall() const;
- static bool lastArgumentIsOutputValue(Operation::Kind m);
- static bool changesContext(Operation::Kind m);
- static bool isPure(Operation::Kind m);
- static bool canThrow(Operation::Kind m);
- static bool takesEngineAsArg(Operation::Kind m, int arg);
- static bool takesFunctionAsArg(Operation::Kind m, int arg);
- static bool takesFrameAsArg(Operation::Kind m, int arg);
- static void *getMethodPtr(Operation::Kind m);
-
-private:
- Operation::Kind m_callee;
-};
-
-class UnwindDispatchPayload
-{
-public:
- UnwindDispatchPayload(int unwindHandlerOffset, int fallthroughSuccessor)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- , m_fallthroughSuccessor(fallthroughSuccessor)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- int fallthroughSuccessor() const //### unused...
- { return m_fallthroughSuccessor; }
-
- static const UnwindDispatchPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::UnwindDispatch)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<UnwindDispatchPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
- int m_fallthroughSuccessor;
-};
-
-class HandleUnwindPayload
-{
-public:
- HandleUnwindPayload(int unwindHandlerOffset)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- static const HandleUnwindPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::HandleUnwind)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<HandleUnwindPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
-};
-
-class OperationBuilder
-{
- Q_DISABLE_COPY_MOVE(OperationBuilder)
-
- friend class QQmlJS::MemoryPool;
- OperationBuilder(QQmlJS::MemoryPool *graphPool);
-
-public:
- static OperationBuilder *create(QQmlJS::MemoryPool *pool);
- ~OperationBuilder() = delete;
-
- Operation *getConstant(QV4::Value v);
- Operation *getFrameState(uint16_t frameSize);
- Operation *getStart(uint16_t outputCount);
- Operation *getEnd(uint16_t controlInputCount);
- Operation *getParam(unsigned index, Function::StringId name);
- Operation *getRegion(unsigned nControlInputs);
- Operation *getPhi(unsigned nValueInputs);
- Operation *getEffectPhi(unsigned nEffectInputs);
- Operation *getUnwindDispatch(unsigned nControlOutputs, int unwindHandlerOffset, int fallthroughSuccessor);
- Operation *getHandleUnwind(int unwindHandlerOffset);
-
- template<Operation::Kind kind>
- Operation *get() {
- return staticOperation(kind);
- }
-
- Operation *getVASeal(uint16_t nElements);
-
- Operation *getJSVarArgsCall(Operation::Kind kind, uint16_t argc);
- Operation *getJSTailCall(uint16_t argc);
- Operation *getTailCall();
-
- Operation *getCall(Operation::Kind callee);
-
-private:
- QQmlJS::MemoryPool *m_graphPool; // used to store per-graph nodes
- Operation *m_opFrameState = nullptr;
- static Operation *staticOperation(Operation::Kind kind);
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4OPERATION_P_H
diff --git a/src/qml/jit/qv4runtimesupport_p.h b/src/qml/jit/qv4runtimesupport_p.h
deleted file mode 100644
index 0dc6022331..0000000000
--- a/src/qml/jit/qv4runtimesupport_p.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4RUNTIMESUPPORT_P_H
-#define QV4RUNTIMESUPPORT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qv4runtimeapi_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-namespace RuntimeSupport {
-
-template <typename T>
-struct CountArguments {
- static constexpr unsigned count = 0;
-};
-template <typename RetTy, typename... Args>
-struct CountArguments<RetTy (*)(Args... args)> {
- static constexpr unsigned count = sizeof...(Args) ;
-};
-
-template<typename M>
-static constexpr unsigned argumentCount() {
- using type = decltype(&M::call);
- return CountArguments<type>::count;
-}
-
-enum class ArgumentType {
- Invalid,
- Engine,
- Frame,
- Function,
- ValueRef,
- ValueArray,
- ReturnedValue,
- Int,
- Bool,
- Void,
-};
-
-
-template <typename T>
-struct JavaScriptType
-{
- // No default type. We want to make sure everything we do is actually recognized.
-};
-
-template <typename T>
-struct ReturnValue
-{
- // No default type.
-};
-
-template <int I, typename T>
-struct Argument
-{
- // For simplicity, we add a default here. Otherwise we would need to spell out more
- // combinations of I and number of arguments of T.
- static constexpr ArgumentType type = ArgumentType::Invalid;
-};
-
-template <typename RetTy, typename T, typename... Args>
-struct Argument<1, RetTy (*)(T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename T, typename... Args>
-struct Argument<2, RetTy (*)(Arg1, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2, typename T,
- typename... Args>
-struct Argument<3, RetTy (*)(Arg1, Arg2, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename T, typename... Args>
-struct Argument<4, RetTy (*)(Arg1, Arg2, Arg3, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename T, typename... Args>
-struct Argument<5, RetTy (*)(Arg1, Arg2, Arg3, Arg4, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5, typename T, typename... Args>
-struct Argument<6, RetTy (*)(Arg1, Arg2, Arg3, Arg4, Arg5, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename... Args>
-struct ReturnValue<RetTy (*)(Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<RetTy>::type;
-};
-
-template<>
-struct JavaScriptType<QV4::ExecutionEngine *>
-{
- static constexpr ArgumentType type = ArgumentType::Engine;
-};
-
-template<>
-struct JavaScriptType<QV4::CppStackFrame *>
-{
- static constexpr ArgumentType type = ArgumentType::Frame;
-};
-
-template<>
-struct JavaScriptType<QV4::Function *>
-{
- static constexpr ArgumentType type = ArgumentType::Function;
-};
-
-template<>
-struct JavaScriptType<const QV4::Value &>
-{
- static constexpr ArgumentType type = ArgumentType::ValueRef;
-};
-
-template<>
-// We need to pass Value * in order to match a parmeter Value[].
-struct JavaScriptType<QV4::Value *>
-{
- static constexpr ArgumentType type = ArgumentType::ValueArray;
-};
-
-template<>
-struct JavaScriptType<int>
-{
- static constexpr ArgumentType type = ArgumentType::Int;
-};
-
-template<>
-struct JavaScriptType<QV4::Bool>
-{
- static constexpr ArgumentType type = ArgumentType::Bool;
-};
-
-template<>
-struct JavaScriptType<QV4::ReturnedValue>
-{
- static constexpr ArgumentType type = ArgumentType::ReturnedValue;
-};
-
-template<>
-struct JavaScriptType<void>
-{
- static constexpr ArgumentType type = ArgumentType::Void;
-};
-
-template<typename M>
-static constexpr ArgumentType retType() {
- using Type = decltype(&M::call);
- return ReturnValue<Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg1Type() {
- using Type = decltype(&M::call);
- return Argument<1, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg2Type() {
- using Type = decltype(&M::call);
- return Argument<2, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg3Type() {
- using Type = decltype(&M::call);
- return Argument<3, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg4Type() {
- using Type = decltype(&M::call);
- return Argument<4, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg5Type() {
- using Type = decltype(&M::call);
- return Argument<5, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg6Type() {
- using Type = decltype(&M::call);
- return Argument<6, Type>::type;
-}
-
-} // namespace RuntimeSupport
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4RUNTIMESUPPORT_P_H
diff --git a/src/qml/jit/qv4schedulers.cpp b/src/qml/jit/qv4schedulers.cpp
deleted file mode 100644
index 0dffefa951..0000000000
--- a/src/qml/jit/qv4schedulers.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4schedulers_p.h"
-#include "qv4util_p.h"
-#include "qv4graph_p.h"
-#include "qv4blockscheduler_p.h"
-#include "qv4stackframe_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcSched, "qt.v4.ir.scheduling")
-Q_LOGGING_CATEGORY(lcDotCFG, "qt.v4.ir.scheduling.cfg")
-
-static bool needsScheduling(Node *n)
-{
- if (n->operation()->isConstant())
- return false;
- switch (n->opcode()) {
- case Meta::Function: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Phi:
- case Meta::EffectPhi:
- return false;
- default:
- return true;
- }
-}
-
-bool NodeScheduler::canStartBlock(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Start: Q_FALLTHROUGH();
- case Meta::IfTrue:
- case Meta::IfFalse:
- case Meta::Region:
- case Meta::HandleUnwind:
- case Meta::OnException:
- return true;
-
- default:
- return false;
- }
-}
-
-bool NodeScheduler::isControlFlowSplit(Node *node) const
-{
- int nOutputs = node->operation()->controlOutputCount();
- if (nOutputs == 2) {
- // if there is a "missing" control output, it's for exception flow without unwinder
- int controlUses = 0;
- auto uses = node->uses();
- for (auto it = uses.begin(), eit = uses.end(); it != eit; ++it) {
- if (isLive(*it) && it.isUsedAsControl())
- ++controlUses;
- }
- return controlUses == 2;
- }
- return nOutputs > 2;
-}
-
-bool NodeScheduler::isBlockTerminator(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Branch: Q_FALLTHROUGH();
- case Meta::Jump:
- case Meta::Return:
- case Meta::TailCall:
- case Meta::UnwindDispatch:
- case Meta::End:
- return true;
- case Meta::Call:
- return isControlFlowSplit(node);
- default:
- return false;
- }
-}
-
-MIBlock *NodeScheduler::getCommonDominator(MIBlock *one, MIBlock *other) const
-{
- MIBlock::Index a = one->index();
- MIBlock::Index b = other->index();
-
- while (a != b) {
- if (m_dominatorDepthForBlock[a] < m_dominatorDepthForBlock[b])
- b = m_domTree->immediateDominator(b);
- else
- a = m_domTree->immediateDominator(a);
- }
-
- return m_miFunction->block(a);
-}
-
-// For Nodes that end up inside loops, it'd be great if we can move (hoist) them out of the loop.
-// To do that, we need a block that preceeds the loop. (So the block before the loop header.)
-// This function calculates that hoist block if the original block is in a loop.
-MIBlock *NodeScheduler::getHoistBlock(MIBlock *block) const
-{
- if (m_loopInfo->isLoopHeader(block))
- return m_miFunction->block(m_domTree->immediateDominator(block->index()));
-
- // make the loop header a candidate:
- MIBlock *loopHeader = m_loopInfo->loopHeaderFor(block);
- if (loopHeader == nullptr)
- return nullptr; // block is not in a loop
-
- // And now the tricky part: block has to dominate all exits from the loop. If it does not do
- // that, it meanse that there is an exit from the loop that can be reached before block. In
- // that case, hoisting from "block" to "loopHeader" would mean there now is an extra calculation
- // that is not needed for a certain loop exit.
- for (MIBlock *outEdge : m_loopInfo->loopExitsForLoop(loopHeader)) {
- if (getCommonDominator(block, outEdge) != block)
- return nullptr;
- }
-
- return m_miFunction->block(m_domTree->immediateDominator(loopHeader->index()));
-}
-
-NodeScheduler::NodeScheduler(Function *irFunction)
- : m_irFunction(irFunction)
- , m_vregs(irFunction->graph()->nodeCount(), std::numeric_limits<unsigned>::max())
- , m_live(irFunction->graph(), /*collectUses =*/ false /* do explicitly NOT collect uses! */)
-{
-}
-
-MIFunction *NodeScheduler::buildMIFunction()
-{
- m_miFunction = new MIFunction(m_irFunction);
-
- // step 1: build the CFG
- auto roots = buildCFG();
- m_miFunction->renumberBlocks();
- m_miFunction->dump(QStringLiteral("CFG after renumbering"));
-
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->index()
- == MIFunction::StartBlockIndex);
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->instructions().front().opcode()
- == Meta::Start);
-
- // step 2: build the dominator tree
- if (lcDotCFG().isDebugEnabled())
- dumpDotCFG();
- m_domTree.reset(new DominatorTree(m_miFunction));
- m_dominatorDepthForBlock = m_domTree->calculateNodeDepths();
-
- // step 3: find loops
- m_loopInfo.reset(new LoopInfo(*m_domTree.data()));
- m_loopInfo->detectLoops();
-
- // step 4: schedule early
- scheduleEarly(roots);
- showNodesByBlock(QStringLiteral("nodes per block after early scheduling"));
-
- // step 5: schedule late
- scheduleLate(roots);
- showNodesByBlock(QStringLiteral("nodes per block after late scheduling"));
-
- // step 6: schedule instructions in each block
- scheduleNodesInBlock();
-
- m_miFunction->dump(QStringLiteral("MI before block scheduling"));
-
- // step 7: order the basic blocks in the CFG
- BlockScheduler blockScheduler(*m_domTree.data(), *m_loopInfo.data());
- m_miFunction->setBlockOrder(blockScheduler.scheduledBlockSequence());
-
- // we're done
- m_miFunction->renumberInstructions();
- m_miFunction->setVregCount(m_nextVReg);
- m_miFunction->dump(QStringLiteral("MI after scheduling"));
- return m_miFunction;
-}
-
-static Node *splitEdge(Function *irFunction, Node *node, unsigned inputIndex)
-{
- Graph *g = irFunction->graph();
- Node *in = node->input(inputIndex);
- Node *region = g->createNode(g->opBuilder()->getRegion(1), &in, 1);
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &region, 1);
-
- qCDebug(lcSched) << "splitting critical edge from node" << node->id()
- << "to node" << node->input(inputIndex)->id()
- << "by inserting jump node" << jump->id()
- << "and region node" << region->id();
-
- node->replaceInput(inputIndex, jump);
- return jump;
-}
-
-// See Chapter 6.3.1 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-std::vector<Node *> NodeScheduler::buildCFG()
-{
- std::vector<Node *> roots;
- roots.reserve(32);
- NodeWorkList todo(m_irFunction->graph());
-
- auto enqueueControlInputs = [this, &todo](Node *node) {
- for (unsigned i = 0, ei = node->operation()->controlInputCount(); i != ei; ++i) {
- const auto inputIndex = node->operation()->indexOfFirstControl() + i;
- Node *input = node->input(inputIndex);
- Q_ASSERT(input);
- if (node->operation()->kind() == Meta::Region
- && node->operation()->controlInputCount() > 1
- && isControlFlowSplit(input)) {
- // critical edge!
- input = splitEdge(m_irFunction, node, inputIndex);
- m_live.markReachable(input);
- m_live.markReachable(input->controlInput(0));
- }
- if (!isBlockTerminator(input)) {
- auto g = m_irFunction->graph();
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &input, 1);
- node->replaceInput(inputIndex, jump);
- m_live.markReachable(jump);
- qCDebug(lcSched) << "inserting jump node" << jump->id()
- << "between node" << node->id()
- << "and node" << input->id();
- input = jump;
- }
- todo.enqueue(input);
- }
- };
-
- // create the CFG by scheduling control dependencies that start/end blocks:
- todo.enqueue(m_irFunction->graph()->endNode());
- while (Node *node = todo.dequeueNextNodeForVisiting()) {
- Q_ASSERT(isBlockTerminator(node));
-
- if (schedulerData(node)->minimumBlock)
- continue;
-
- MIBlock *b = m_miFunction->addBlock();
-
- qCDebug(lcSched) << "scheduling node" << node->id() << "as terminator for new block"
- << b->index();
- b->instructions().push_front(createMIInstruction(node));
- placeFixed(node, b, Schedule);
- roots.push_back(node);
-
- if (Node *framestate = node->frameStateInput()) {
- placeFixed(framestate, b, DontSchedule);
- qCDebug(lcSched) << ".. also scheduling framestate dependency node" << node->id()
- << "in block" << b->index();
- }
-
- if (node->opcode() == Meta::End) {
- enqueueControlInputs(node);
- continue;
- }
-
- while (true) {
- Node *controlDependency = node->controlInput(0);
- if (!controlDependency)
- break;
- if (todo.isVisited(controlDependency))
- break;
- if (schedulerData(controlDependency)->isFixed)
- break;
-
- if (controlDependency->opcode() == Meta::Start) {
- qCDebug(lcSched) << "placing start node" << controlDependency->id()
- << "in block" << b->index();
- handleStartNode(controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- break; // we're done with this block
- }
- if (isBlockTerminator(controlDependency)) {
- qCDebug(lcSched) << "found terminator node" << controlDependency->id()
- << "for another block, so finish block" << b->index();
- Node *merge = m_irFunction->graph()->createNode(
- m_irFunction->graph()->opBuilder()->getRegion(1), &controlDependency, 1);
- node->replaceInput(node->operation()->indexOfFirstControl(), merge);
- addBlockStart(roots, merge, b);
- placeFixed(merge, b, Schedule);
- m_live.markReachable(merge);
- todo.enqueue(controlDependency);
- break; // we're done with this block
- }
- if (canStartBlock(controlDependency)
- || schedulerData(controlDependency->controlInput())->isFixed) {
- qCDebug(lcSched) << "found block start node" << controlDependency->id()
- << "for this block, so finish block" << b->index();
- addBlockStart(roots, controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- enqueueControlInputs(controlDependency);
- break; // we're done with this block
- }
- qCDebug(lcSched) << "skipping node" << controlDependency->id();
- node = controlDependency;
- }
- }
-
- // link the edges of the MIBlocks, and add basic-block arguments:
- for (MIBlock *toBlock : m_miFunction->blocks()) {
- Q_ASSERT(!toBlock->instructions().empty());
- MIInstr &instr = toBlock->instructions().front();
- Node *toNode = instr.irNode();
- const auto opcode = toNode->operation()->kind();
- if (opcode == Meta::Region) {
- unsigned inputNr = 0;
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- MIInstr &fromTerminator = fromBlock->instructions().back();
- if (fromTerminator.irNode()->opcode() == Meta::Jump ||
- fromTerminator.irNode()->opcode() == Meta::UnwindDispatch) {
- unsigned arg = 0;
- for (const MIOperand &bbArg : toBlock->arguments()) {
- fromTerminator.setOperand(arg++,
- createMIOperand(bbArg.irNode()->input(inputNr)));
- }
- }
- ++inputNr;
- }
- } else if (opcode == Meta::End) {
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- } else if (Node *fromNode = toNode->controlInput()) {
- MIBlock *fromBlock = schedulerData(fromNode)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- }
-
- m_irFunction->dump(QStringLiteral("graph after building CFG"));
-
- auto startBlock = schedulerData(m_irFunction->graph()->startNode())->minimumBlock;
- m_miFunction->setStartBlock(startBlock);
-
- if (lcSched().isDebugEnabled())
- m_miFunction->dump(QStringLiteral("control flow graph before renumbering"));
- m_miFunction->verifyCFG();
-
- return roots;
-}
-
-// See Chapter 6.3.3 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-void NodeScheduler::scheduleEarly(const std::vector<Node *> &roots)
-{
- // scheduling one node might have the effect of queueing its dependencies
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots) {
- todo.enqueue(root);
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleEarly(node, todo);
- }
-}
-
-void NodeScheduler::scheduleEarly(Node *node, NodeWorkList &todo)
-{
- qCDebug(lcSched) << "Scheduling node" << node->id() << "early...";
-
- SchedulerData *sd = schedulerData(node);
-
- if (sd->isFixed) {
- // Fixed nodes already know their schedule early position.
- qCDebug(lcSched) << ".. Fixed node" << node->id() << "is on minimum block"
- << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[sd->minimumBlock->index()];
- }
-
- for (Node *use : node->uses()) {
- if (isLive(use))
- propagateMinimumPosition(sd->minimumBlock, use, todo);
- else
- qCDebug(lcSched) << ".. Skipping node" << use->id() << "as it's not live";
- }
-}
-
-void NodeScheduler::propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode,
- NodeWorkList &todo)
-{
- Q_ASSERT(newMinimumPosition);
-
- SchedulerData *sd = schedulerData(toNode);
- if (sd->isFixed) // nothing to do
- return;
-
- MIBlock::Index minimumBlockIndex = sd->minimumBlock
- ? sd->minimumBlock->index()
- : MIFunction::StartBlockIndex;
- Q_ASSERT(m_domTree->insideSameDominatorChain(newMinimumPosition->index(), minimumBlockIndex));
- if (sd->minimumBlock == nullptr
- || m_dominatorDepthForBlock[newMinimumPosition->index()]
- > m_dominatorDepthForBlock[minimumBlockIndex]) {
- // ok, some input for toNode is scheduled *after* our current minimum depth, so we need
- // to adjust out minimal position. (This might involve rescheduling toNode's uses.)
- place(toNode, newMinimumPosition);
- todo.reEnqueue(toNode);
- qCDebug(lcSched) << ".. Propagating minimum block" << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[newMinimumPosition->index()]
- << "to use node" << toNode->id();
- } else {
- qCDebug(lcSched) << ".. Minimum position" << newMinimumPosition->index()
- << "is not better than" << minimumBlockIndex
- << "for node" << toNode->id();
- }
-}
-
-// See Chapter 6.3.4 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-//
-// There is one extra detail not described in the thesis mentioned above: loop hoisting. Before we
-// place a node in the latest block that dominates all uses, we check if we accidentally sink it
-// *into* a loop (meaning the latest block is inside a loop, where it is not if the earliest
-// possible block would be chosen). If we detect that a nodes is going to sink into a loop, we walk
-// the dominator path from the latest block up to the earliest block, and pick the first block that
-// is in the same loop (if any) as the earlieast block.
-//
-// As noted in the thesis, this strategy might enlongen life times, which could be harmful for
-// values that are simple to re-materialized or re-calculate.
-void NodeScheduler::scheduleLate(const std::vector<Node *> &roots)
-{
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots)
- todo.enqueue(root);
-
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleNodeLate(node, todo);
-}
-
-void NodeScheduler::scheduleNodeLate(Node *node, NodeWorkList &todo)
-{
- if (!needsScheduling(node))
- return;
- qCDebug(lcSched) << "Scheduling node" << node->id() << "late...";
-
- auto sd = schedulerData(node);
- if (sd->unscheduledUses == SchedulerData::NotYetCalculated) {
- sd->unscheduledUses = 0;
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isFixed)
- continue;
- todo.enqueue(use);
- ++sd->unscheduledUses;
- }
- }
-
- if (sd->isFixed) {
- qCDebug(lcSched) << ".. it's fixed";
- enqueueInputs(node, todo);
- return;
- }
-
- if (sd->unscheduledUses) {
- qCDebug(lcSched).noquote() << ".. not all uses are fixed, postpone it."<< todo.status(node);
- return;
- }
-
- MIBlock *&minBlock = sd->minimumBlock;
- if (minBlock == nullptr)
- minBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- MIBlock *commonUseDominator = commonDominatorOfUses(node);
- qCDebug(lcSched) << ".. common use dominator: block" << commonUseDominator->index();
-
- // the minBlock has to dominate the uses, *and* the common dominator of the uses.
- Q_ASSERT(minBlock->index() == commonUseDominator->index() ||
- m_domTree->dominates(minBlock->index(), commonUseDominator->index()));
-
- // we now found the deepest block, so use it as the target block:
- MIBlock *targetBlock = commonUseDominator;
-
- if (node->opcode() == Meta::FrameState) {
- // never hoist framestates: they're used (among other things) to keep their inputs alive, so
- // hoisting them out would end the life-time of those inputs prematurely
- } else {
- // but we want to prevent blocks sinking into loops unnecessary
- MIBlock *hoistBlock = getHoistBlock(targetBlock);
- while (hoistBlock
- && m_dominatorDepthForBlock[hoistBlock->index()]
- >= m_dominatorDepthForBlock[minBlock->index()]) {
- qCDebug(lcSched) << ".. hoisting node" << node->id() << "from block"
- << targetBlock->index() << "to block" << hoistBlock->index();
- // ok, so there a) is a hoist block and b) it's deeper than the minimum block,
- // so lift it up one level ...
- targetBlock = hoistBlock;
- // ... and see if we can lift it one more level
- hoistBlock = getHoistBlock(targetBlock);
- }
- }
-
- qCDebug(lcSched) << ".. fixating it in block" << targetBlock->index()
- << "where the minimum block was" << minBlock->index();
-
- placeFixed(node, targetBlock, DontSchedule);
- enqueueInputs(node, todo);
-}
-
-void NodeScheduler::enqueueInputs(Node *node, NodeWorkList &todo)
-{
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto sd = schedulerData(input);
- if (sd->isFixed)
- continue;
- qCDebug(lcSched).noquote() << "... enqueueing input node" << input->id()
- << todo.status(input);
- if (sd->unscheduledUses != SchedulerData::NotYetCalculated) {
- if (sd->unscheduledUses > 0)
- --sd->unscheduledUses;
- if (sd->unscheduledUses == 0)
- todo.reEnqueue(input);
- } else {
- todo.reEnqueue(input);
- }
- }
-}
-
-Node *NodeScheduler::firstNotFixedUse(Node *node)
-{
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!schedulerData(use)->isFixed)
- return use;
- }
- return nullptr;
-}
-
-MIBlock *NodeScheduler::commonDominatorOfUses(Node *node)
-{
- MIBlock *commonDominator = nullptr;
- for (auto useIt = node->uses().begin(), useEIt = node->uses().end(); useIt != useEIt; ++useIt) {
- Node *use = *useIt;
- if (!isLive(use))
- continue;
- // region nodes use other nodes through their control dependency. But those nodes should
- // already have been placed as block terminators before.
- Q_ASSERT(use->opcode() != Meta::Region);
- if (use->opcode() == Meta::Phi || use->opcode() == Meta::EffectPhi) {
- // find the predecessor block defining this input
- Node *region = use->controlInput(0);
- Node *input = region->controlInput(useIt.inputIndex());
- use = input;
- }
- auto minBlock = schedulerData(use)->minimumBlock;
- if (commonDominator == nullptr)
- commonDominator = minBlock;
- else
- commonDominator = getCommonDominator(commonDominator, minBlock);
- }
- return commonDominator;
-}
-
-void NodeScheduler::scheduleNodesInBlock()
-{
- auto startBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- for (Node *n : m_live.reachable()) {
- auto sd = schedulerData(n);
- if (!sd->minimumBlock)
- sd->minimumBlock = startBlock;
- }
-
- std::vector<std::vector<SchedulerData *>> nodesForBlock;
- nodesForBlock.resize(m_miFunction->blockCount());
-
- for (auto sd : m_schedulerData) {
- if (sd == nullptr)
- continue;
- if (!isLive(sd->node))
- continue;
- sd->unscheduledUses = 0;
- for (Node *use : sd->node->uses()) {
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isScheduledInBlock)
- continue;
- if (schedulerData(use)->minimumBlock == sd->minimumBlock)
- ++sd->unscheduledUses;
- }
- if (sd->unscheduledUses == 0)
- nodesForBlock[sd->minimumBlock->index()].push_back(sd);
- }
-
- NodeWorkList todo(m_irFunction->graph());
- for (MIBlock *b : m_miFunction->blocks()) {
- qCDebug(lcSched) << "Scheduling inside block" << b->index();
- MIInstr *insertionPoint = &b->instructions().back();
- todo.enqueue(insertionPoint->irNode());
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- for (auto sd : nodesForBlock[b->index()]) {
- if (!sd->isScheduledInBlock)
- todo.enqueue(sd->node);
- }
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- todo.reset();
- }
-}
-
-void NodeScheduler::scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo)
-{
- while (Node *n = todo.dequeueNextNodeForVisiting())
- scheduleNodeInBlock(n, insertionPoint, b, todo);
-}
-
-void NodeScheduler::scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b,
- NodeWorkList &todo)
-{
- Q_ASSERT(!node->isDead());
-
- if (!isLive(node))
- return;
-
- if (!needsScheduling(node))
- return;
-
- auto nodeData = schedulerData(node);
- if (nodeData->minimumBlock != b)
- return;
-
- const bool wasAlreadyScheduled = nodeData->isScheduledInBlock;
- if (!wasAlreadyScheduled) {
- if (nodeData->unscheduledUses)
- return;
-
- scheduleNodeNow(node, insertionPoint);
- }
-
- if (Node *framestate = node->frameStateInput())
- scheduleNodeInBlock(framestate, insertionPoint, b, todo);
-
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto inputInfo = schedulerData(input);
- if (inputInfo->isScheduledInBlock)
- continue;
- Q_ASSERT(inputInfo->minimumBlock != nullptr);
- if (inputInfo->minimumBlock != b)
- continue;
- Q_ASSERT(!input->isDead());
- Q_ASSERT(inputInfo->unscheduledUses != SchedulerData::NotYetCalculated);
- if (!wasAlreadyScheduled && inputInfo->unscheduledUses > 0)
- --inputInfo->unscheduledUses;
- if (inputInfo->unscheduledUses == 0)
- todo.enqueue(input);
- }
-}
-
-void NodeScheduler::scheduleNodeNow(Node *node, MIInstr *&insertionPoint)
-{
- qCDebug(lcSched) << ".. scheduling node" << node->id()
- << "in block" << insertionPoint->parent()->index()
- << "before node" << insertionPoint->irNode()->id();
-
- MIInstr *newInstr = createMIInstruction(node);
- newInstr->insertBefore(insertionPoint);
- insertionPoint = newInstr;
-}
-
-void NodeScheduler::place(Node *node, MIBlock *b)
-{
- Q_ASSERT(!node->isDead());
-
- if (b == nullptr)
- return;
-
- schedulerData(node)->minimumBlock = b;
-}
-
-void NodeScheduler::placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled)
-{
- place(node, b);
- auto sd = schedulerData(node);
- Q_ASSERT(!sd->isFixed);
- sd->isFixed = true;
- sd->isScheduledInBlock = markScheduled == Schedule;
-}
-
-unsigned NodeScheduler::vregForNode(Node *node)
-{
- unsigned &vreg = m_vregs[unsigned(node->id())];
- if (vreg == std::numeric_limits<unsigned>::max())
- vreg = m_nextVReg++;
- return vreg;
-}
-
-void NodeScheduler::addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block)
-{
- block->instructions().insert(block->instructions().begin(), createMIInstruction(startNode));
- if (startNode->opcode() == Meta::Region) {
- for (Node *use : startNode->uses()) {
- if (use->opcode() == Meta::Phi && isLive(use)) {
- block->addArgument(MIOperand::createVirtualRegister(use, vregForNode(use)));
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- } else if (use->opcode() == Meta::EffectPhi && isLive(use)) {
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- }
- }
- }
-}
-
-void NodeScheduler::handleStartNode(Node *startNode, MIBlock *startBlock)
-{
- startBlock->instructions().push_front(createMIInstruction(startNode));
-
- QVarLengthArray<Node *, 32> args;
- for (Node *use : startNode->uses()) {
- switch (use->opcode()) {
- case Meta::Engine: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Function:
- placeFixed(use, startBlock, Schedule);
- break;
- case Meta::Parameter: {
- auto param = ParameterPayload::get(*use->operation());
- int idx = int(param->parameterIndex());
- if (args.size() <= idx)
- args.resize(idx + 1);
- args[int(idx)] = use;
- placeFixed(use, startBlock, Schedule);
- }
- break;
- default:
- break;
- }
- }
-
- for (unsigned i = 0, ei = unsigned(args.size()); i != ei; ++i) {
- if (Node *arg = args.at(int(i)))
- startBlock->addArgument(MIOperand::createJSStackSlot(arg, i));
- }
-}
-
-static Node *firstControlOutput(Node *n)
-{
- for (auto it = n->uses().begin(), eit = n->uses().end(); it != eit; ++it) {
- if (it.isUsedAsControl())
- return *it;
- }
- return nullptr;
-}
-
-MIInstr *NodeScheduler::createMIInstruction(Node *node)
-{
- const auto opcode = node->operation()->kind();
-
- unsigned nArgs = 0;
- switch (opcode) {
- case Meta::UnwindDispatch: Q_FALLTHROUGH();
- case Meta::Jump: {
- Node *target = firstControlOutput(node);
- if (target->opcode() == Meta::Region) {
- for (Node *n : target->uses()) {
- if (n->opcode() == Meta::Phi && isLive(n))
- ++nArgs;
- }
- }
- }
- break;
- case Meta::Branch:
- nArgs = 1;
- break;
- case Meta::Return:
- nArgs = 1;
- break;
- default:
- nArgs = node->operation()->valueInputCount();
- break;
- }
-
- MIInstr *instr = MIInstr::create(m_irFunction->pool(), node, nArgs);
- for (unsigned i = 0, ei = node->operation()->valueInputCount(); i != ei; ++i)
- instr->setOperand(i, createMIOperand(node->input(i)));
- if (node->opcode() != Meta::Start && node->operation()->valueOutputCount() > 0)
- instr->setDestination(createMIOperand(node));
-
- schedulerData(node)->isScheduledInBlock = true;
- return instr;
-}
-
-MIOperand NodeScheduler::createMIOperand(Node *node)
-{
- if (node->operation()->isConstant())
- return MIOperand::createConstant(node);
-
- auto opcode = node->operation()->kind();
- switch (opcode) {
- case Meta::Parameter:
- return MIOperand::createJSStackSlot(
- node, unsigned(ParameterPayload::get(*node->operation())->parameterIndex()));
- case Meta::Engine:
- return MIOperand::createEngineRegister(node);
- case Meta::CppFrame:
- return MIOperand::createCppFrameRegister(node);
- case Meta::Function:
- return MIOperand::createFunction(node);
- default:
- if ((node->opcode() == Meta::Call
- && CallPayload::get(*node->operation())->callee() == Meta::JSThisToObject)
- || node->opcode() == Meta::StoreThis) {
- return MIOperand::createJSStackSlot(node, CallData::This);
- } else {
- return MIOperand::createVirtualRegister(node, vregForNode(node));
- }
- }
-}
-
-void NodeScheduler::showNodesByBlock(const QString &description) const
-{
- if (!lcSched().isDebugEnabled())
- return;
-
- qCDebug(lcSched) << description;
-
- for (MIBlock *b : m_miFunction->blocks()) {
- QString s;
- for (const SchedulerData *sd : m_schedulerData) {
- if (!sd)
- continue;
- if (!isLive(sd->node))
- continue;
- if (sd->minimumBlock == b) {
- if (!s.isEmpty())
- s += QStringLiteral(", ");
- s += QStringLiteral("%1 (%2)").arg(QString::number(sd->node->id()),
- sd->node->operation()->debugString());
- }
- }
- if (s.isEmpty())
- s = QStringLiteral("<<none>>");
- qCDebug(lcSched, "Nodes in block %u: %s", b->index(), s.toUtf8().constData());
- }
-}
-
-void NodeScheduler::dumpDotCFG() const
-{
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"L%1\" label=\"Control Flow Graph\";"
- "node[shape=circle];edge[dir=forward fontsize=10]\n")
- .arg(MIFunction::StartBlockIndex);
- for (MIBlock *src : m_miFunction->blocks()) {
- for (MIBlock *dst : src->outEdges()) {
- out += QStringLiteral("L%1->L%2\n").arg(QString::number(src->index()),
- QString::number(dst->index()));
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotCFG).nospace().noquote() << out;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4schedulers_p.h b/src/qml/jit/qv4schedulers_p.h
deleted file mode 100644
index f9179816df..0000000000
--- a/src/qml/jit/qv4schedulers_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4SCHEDULER_P_H
-#define QV4SCHEDULER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4global_p.h"
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Node scheduling "flattens" the graph into basic blocks with an ordered list of instructions.
-//
-// The various steps are mentioned in buildMIFunction, but the general idea is described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf in chapter 6.
-class NodeScheduler final
-{
- Q_DISABLE_COPY_MOVE(NodeScheduler)
-
- class SchedulerData final {
- Q_DISABLE_COPY_MOVE(SchedulerData)
- public:
- static SchedulerData *create(QQmlJS::MemoryPool *pool)
- { return pool->New<SchedulerData>(); }
-
- SchedulerData() = default;
- ~SchedulerData() = default;
-
- Node *node = nullptr;
- MIBlock *minimumBlock = nullptr;
- bool isFixed = false;
- bool isScheduledInBlock = false;
- static constexpr unsigned NotYetCalculated = std::numeric_limits<unsigned>::max();
- unsigned unscheduledUses = NotYetCalculated;
- };
-
-public:
- NodeScheduler(Function *irFunction);
- ~NodeScheduler() = default;
-
- MIFunction *buildMIFunction();
-
-private:
- std::vector<Node *> buildCFG();
- void scheduleEarly(const std::vector<Node *> &roots);
- void scheduleEarly(Node *node, NodeWorkList &todo);
- void propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode, NodeWorkList &todo);
- void scheduleLate(const std::vector<Node *> &roots);
- void scheduleNodeLate(Node *node, NodeWorkList &todo);
- void enqueueInputs(Node *node, NodeWorkList &todo);
- Node *firstNotFixedUse(Node *node);
- MIBlock *commonDominatorOfUses(Node *node);
- void scheduleNodesInBlock();
- void scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeNow(Node *node, MIInstr *&insertionPoint);
-
- void place(Node *node, MIBlock *b);
- enum ScheduleOrNot { DontSchedule, Schedule };
- void placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled);
- unsigned vregForNode(Node *node);
- void addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block);
- void enqueueControlInputs(Node *node);
- void handleStartNode(Node *startNode, MIBlock *startBlock);
- MIInstr *createMIInstruction(Node *node);
- MIOperand createMIOperand(Node *node);
- SchedulerData *schedulerData(Node *n)
- {
- if (Q_UNLIKELY(m_schedulerData.size() <= n->id()))
- m_schedulerData.resize(n->id() + 8);
- SchedulerData *&sd = m_schedulerData[n->id()];
- if (Q_UNLIKELY(sd == nullptr)) {
- sd = SchedulerData::create(m_irFunction->pool());
- sd->node = n;
- }
- return sd;
- }
- bool isLive(Node *n) const
- { return m_live.isReachable(n->id()); }
- bool canStartBlock(Node *node) const;
- bool isControlFlowSplit(Node *node) const;
- bool isBlockTerminator(Node *node) const;
- MIBlock *getCommonDominator(MIBlock *one, MIBlock *other) const;
- MIBlock *getHoistBlock(MIBlock *block) const;
-
- void showNodesByBlock(const QString &description) const;
-
- void dumpDotCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- MIFunction *m_miFunction = nullptr;
- QScopedPointer<LoopInfo> m_loopInfo;
- QScopedPointer<DominatorTree> m_domTree;
- std::vector<int> m_dominatorDepthForBlock;
- std::vector<unsigned> m_vregs;
- std::vector<SchedulerData *> m_schedulerData;
- NodeCollector m_live;
- unsigned m_nextVReg = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4SCHEDULER_P_H
diff --git a/src/qml/jit/qv4tracingjit.cpp b/src/qml/jit/qv4tracingjit.cpp
deleted file mode 100644
index c8974b3a1b..0000000000
--- a/src/qml/jit/qv4tracingjit.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4vme_moth_p.h"
-#include "qv4graphbuilder_p.h"
-#include "qv4lowering_p.h"
-#include "qv4mi_p.h"
-#include "qv4schedulers_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTracing, "qt.v4.tracing")
-
-namespace QV4 {
-
-// This is the entry point for the "tracing JIT". It uses the sea-of-nodes concept as described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf
-//
-// The minimal pipeline is as follows:
-// - create the graph for the function
-// - do generic lowering
-// - schedule the nodes
-// - run minimal stack slot allocation (no re-use of slots)
-// - run the assembler
-//
-// This pipeline has no optimizations, and generates quite inefficient code. It does have the
-// advantage that no trace information is used, so it can be used for testing where it replaces
-// the baseline JIT. Any optimizations are additions to this pipeline.
-//
-// Note: generators (or resuming functions in general) are not supported by this JIT.
-void Moth::runTracingJit(QV4::Function *function)
-{
- IR::Function irFunction(function);
- qCDebug(lcTracing).noquote() << "runTracingJit called for" << irFunction.name() << "...";
-
- qCDebug(lcTracing).noquote().nospace() << function->traceInfoToString();
-
- IR::GraphBuilder::buildGraph(&irFunction);
- irFunction.dump(QStringLiteral("initial IR"));
- irFunction.verify();
-
- IR::GenericLowering(irFunction).lower();
- irFunction.dump(QStringLiteral("after generic lowering"));
- irFunction.verify();
-
- IR::NodeScheduler scheduler(&irFunction);
- QScopedPointer<IR::MIFunction> miFunction(scheduler.buildMIFunction());
- miFunction->dump(QStringLiteral("initial MI"));
- irFunction.verify();
-}
-
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index aab72f8b2d..45ea79d31a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -470,6 +470,33 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
QV4::GlobalExtensions::init(obj, extensions);
}
+/*!
+ \since 5.14
+ Interrupts or re-enables JavaScript execution.
+
+ If \a interrupted is \c true, any JavaScript executed by this engine
+ immediately aborts and returns an error object until this function is
+ called again with a value of \c false for \a interrupted.
+
+ This function is thread safe. You may call it from a different thread
+ in order to interrupt, for example, an infinite loop in JavaScript.
+*/
+void QJSEngine::setInterrupted(bool interrupted)
+{
+ m_v4Engine->isInterrupted = interrupted;
+}
+
+/*!
+ \since 5.14
+ Returns whether JavaScript execution is currently interrupted.
+
+ \sa setInterrupted()
+*/
+bool QJSEngine::isInterrupted() const
+{
+ return m_v4Engine->isInterrupted;
+}
+
static QUrl urlForFileName(const QString &fileName)
{
if (!fileName.startsWith(QLatin1Char(':')))
@@ -527,6 +554,8 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
result = script.run();
if (scope.engine->hasException)
result = v4->catchException();
+ if (v4->isInterrupted)
+ result = v4->newErrorObject(QStringLiteral("Interrupted"));
QJSValue retval(v4, result->asReturnedValue());
@@ -565,7 +594,12 @@ QJSValue QJSEngine::importModule(const QString &fileName)
if (m_v4Engine->hasException)
return QJSValue(m_v4Engine, m_v4Engine->catchException());
moduleUnit->evaluate();
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+ if (!m_v4Engine->isInterrupted)
+ return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+
+ return QJSValue(
+ m_v4Engine,
+ m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
}
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6300842341..31a4d68baa 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -113,6 +113,9 @@ public:
void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
+ void setInterrupted(bool interrupted);
+ bool isInterrupted() const;
+
QV4::ExecutionEngine *handle() const { return m_v4Engine; }
void throwError(const QString &message);
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index e0bd986920..92eaf1d8ee 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -769,6 +769,8 @@ QJSValue QJSValue::call(const QJSValueList &args)
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -825,6 +827,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -873,6 +877,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 5b9934282c..a87eb92caf 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -96,7 +96,7 @@ struct DateObject: Object {
double date() const { return d()->date; }
void setDate(double date) { d()->date = date; }
- QDateTime toQDateTime() const;
+ Q_QML_PRIVATE_EXPORT QDateTime toQDateTime() const;
};
template<>
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 18927c637c..e10bf3cf79 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -138,8 +138,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTracingAll, "qt.v4.tracing.all")
-
using namespace QV4;
#ifndef V4_BOOTSTRAP
@@ -165,7 +163,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(nullptr)
, m_multiplyWrappedQObjects(nullptr)
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
, m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
#endif
{
@@ -175,7 +173,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
-#ifdef QT_NO_DEBUG
+#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer)
maxCallDepth = 1234;
#else
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
@@ -658,13 +656,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ExecutionEngine::~ExecutionEngine()
{
- if (Q_UNLIKELY(lcTracingAll().isDebugEnabled())) {
- for (auto cu : compilationUnits) {
- for (auto f : qAsConst(cu->runtimeFunctions))
- qCDebug(lcTracingAll).noquote().nospace() << f->traceInfoToString();
- }
- }
-
modules.clear();
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = nullptr;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 6df4545014..d0c58eee8f 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -464,7 +464,7 @@ public:
// but any time a QObject is wrapped a second time in another engine, we have to do
// bookkeeping.
MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
const bool m_canAllocateExecutableMemory;
#endif
@@ -595,7 +595,7 @@ public:
bool canJIT(Function *f = nullptr)
{
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
if (!m_canAllocateExecutableMemory)
return false;
if (f)
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index b5cfea8863..82eccd9f3c 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -69,9 +69,23 @@ struct Q_QML_EXPORT EngineBase {
CppStackFrame *currentStackFrame = nullptr;
Value *jsStackTop = nullptr;
+
+ // The JIT expects hasException and isInterrupted to be in the same 32bit word in memory.
quint8 hasException = false;
- quint8 writeBarrierActive = false;
+ // isInterrupted is expected to be set from a different thread
+#if defined(Q_ATOMIC_INT8_IS_SUPPORTED)
+ QAtomicInteger<quint8> isInterrupted = false;
quint16 unused = 0;
+#elif defined(Q_ATOMIC_INT16_IS_SUPPORTED)
+ quint8 unused = 0;
+ QAtomicInteger<quint16> isInterrupted = false;
+#elif defined(V4_BOOTSTRAP)
+ // We don't need the isInterrupted flag when bootstrapping.
+ quint8 unused[3];
+#else
+# error V4 needs either 8bit or 16bit atomics.
+#endif
+
quint8 isExecutingInRegExpJIT = false;
quint8 padding[3];
MemoryManager *memoryManager = nullptr;
@@ -137,6 +151,10 @@ Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsSta
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8);
Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
+#ifndef V4_BOOTSTRAP
+Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4);
+#endif
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 1bd4329fe8..debdf23d27 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -75,19 +75,12 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg
Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
{
- quint16 traceSlotCount = 0;
-#if QT_CONFIG(qml_tracing)
- traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing()
- ? 1
- : function->nTraceInfos;
-#endif
- quint8 *storage = new quint8[sizeof(Function) + traceSlotCount];
- return new(storage) Function(engine, unit, function);
+ return new Function(engine, unit, function);
}
void Function::destroy()
{
- delete[] reinterpret_cast<quint8 *>(this);
+ delete this;
}
Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
@@ -111,13 +104,6 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
-
-#if QT_CONFIG(qml_tracing)
- if (tracingEnabled()) {
- for (uint i = 0; i < function->nTraceInfos; ++i)
- *traceInfo(i) = 0;
- }
-#endif
}
Function::~Function()
@@ -188,22 +174,4 @@ QQmlSourceLocation Function::sourceLocation() const
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
-QString Function::traceInfoToString()
-{
- QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':');
- if (!tracingEnabled())
- return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount);
- if (compiledFunction->nTraceInfos == 0)
- return info + QLatin1String(" none.\n");
-
- info += QLatin1Char('\n');
- for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) {
- auto bits = QString::number(*traceInfo(i), 2);
- if (bits.size() < 8)
- bits.prepend(QString(8 - bits.size(), '0'));
- info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits);
- }
- return info;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index f8125a58f8..01b212370d 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -123,31 +123,6 @@ public:
return nullptr;
return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
}
-
- Q_NEVER_INLINE QString traceInfoToString();
-
- quint8 *traceInfo(uint i)
- {
-#if QT_CONFIG(qml_tracing)
- Q_ASSERT((tracingEnabled() && i < traceInfoCount()) || (i == 0));
- return reinterpret_cast<quint8 *>(this) + sizeof(Function) + i;
-#else
- Q_UNUSED(i);
- return nullptr;
-#endif
- }
-
- quint32 traceInfoCount() const
- { return compiledFunction->nTraceInfos; }
-
- bool tracingEnabled() const
- {
-#if QT_CONFIG(qml_tracing)
- return traceInfoCount() != CompiledData::Function::NoTracing();
-#else
- return false;
-#endif
- }
};
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index e03d49c74d..4fee26f341 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -87,11 +87,11 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
}
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call);
- void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- void init(QV4::ExecutionContext *scope, const QString &name);
- void init();
- void destroy();
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_PRIVATE_EXPORT void init();
+ Q_QML_PRIVATE_EXPORT void destroy();
void setFunction(Function *f);
@@ -260,7 +260,7 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct IndexedBuiltinFunction : FunctionObject
+struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
};
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d47393b3bb..42b6edb6e2 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -82,53 +82,9 @@ inline bool isfinite(double d) { return _finite(d); }
inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#endif
-// Decide whether to enable or disable the JIT
-
-// White list architectures
-//
-// NOTE: This should match the logic in qv4targetplatform_p.h!
-
-#if defined(Q_PROCESSOR_X86_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_INTEGRITY))
-# if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4)
-# define V4_ENABLE_JIT
-# elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 // clang 3.5 and later will set this if the core supports the Thumb-2 ISA.
-# define V4_ENABLE_JIT
-# endif
-#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8)
-# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_INTEGRITY)
-# define V4_ENABLE_JIT
-# endif
-//#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
-//# define V4_ENABLE_JIT
-#endif
-
-// check FPU with double precision on ARM platform
-#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04)
-# undef V4_ENABLE_JIT
-#endif
-
-// Black list some platforms
-#if defined(V4_ENABLE_JIT)
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-# undef V4_ENABLE_JIT
-#endif
-#endif
-
-// For debug purposes: add CONFIG+=force-compile-jit to qmake's command-line to always compile the JIT.
-#if defined(V4_FORCE_COMPILE_JIT) && !defined(V4_ENABLE_JIT)
-# define V4_ENABLE_JIT
-#endif
-
// Do certain things depending on whether the JIT is enabled or disabled
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
#define ENABLE_YARR_JIT 1
#define ENABLE_JIT 1
#define ENABLE_ASSEMBLER 1
@@ -280,20 +236,6 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
-enum class ObservedTraceValues : quint8 {
- Integer = 1 << 0,
- Boolean = 1 << 1,
- Double = 1 << 2,
- Other = 1 << 3,
- TypeMask = Integer | Boolean | Double | Other,
-
- TruePathTaken = 1 << 0,
- FalsePathTaken = 1 << 1,
-
- ArrayWasAccessed = 1 << 7,
- ArrayAccessNeededFallback = 1 << 6,
-};
-
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 5db5bd46ec..f9bc7b68c6 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -39,29 +39,19 @@
#include "qv4identifier_p.h"
#include "qv4identifiertable_p.h"
#include "qv4string_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits)
: size(0)
, numBits(numBits)
, identifierTable(table)
{
refCount.store(1);
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
identifierTable->addIdentifierHash(this);
@@ -110,7 +100,7 @@ IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
if (grow) {
++d->numBits;
- int newAlloc = primeForNumBits(d->numBits);
+ int newAlloc = qPrimeForNumBits(d->numBits);
IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
for (int i = 0; i < d->alloc; ++i) {
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index ae937b2889..21b47c3909 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -38,28 +38,18 @@
****************************************************************************/
#include "qv4identifiertable_p.h"
#include "qv4symbol_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierTable::IdentifierTable(ExecutionEngine *engine, int numBits)
: engine(engine)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entriesByHash = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
entriesById = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
memset(entriesByHash, 0, alloc*sizeof(Heap::String *));
@@ -87,7 +77,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
if (grow) {
++numBits;
- int newAlloc = primeForNumBits(numBits);
+ int newAlloc = qPrimeForNumBits(numBits);
Heap::StringOrSymbol **newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *));
memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *));
for (uint i = 0; i < alloc; ++i) {
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index a10fda79f2..d597335031 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -45,27 +45,18 @@
#include "qv4identifiertable_p.h"
#include "qv4value_p.h"
#include "qv4mm_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
PropertyHashData::PropertyHashData(int numBits)
: refCount(1)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
}
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index c2c3fa0474..99f425293e 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -242,9 +242,6 @@ ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *eng
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset2)->asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -260,9 +257,6 @@ ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -278,9 +272,6 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng
return o->memberData->values.data()[l->objectLookupTwoClasses.offset].asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -296,9 +287,7 @@ ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine,
return l->protoLookupTwoClasses.data->asReturnedValue();
if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
return l->protoLookupTwoClasses.data2->asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
+ return getterFallback(l, engine, object);
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 7309749a81..f2e0afd797 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Lookup {
+struct Q_QML_PRIVATE_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index a60a49a811..90246c4229 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -66,42 +66,27 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(add_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(add_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(sub_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(sub_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(mul_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(mul_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 567382cbc0..38055ef407 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -410,7 +410,7 @@ private:
friend struct ObjectPrototype;
};
-struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
+struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
{
uint arrayIndex = 0;
uint memberIndex = 0;
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index 523afd4ccf..b2a2ec3dea 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -124,7 +124,7 @@ public:
return m();
}
- bool isString() const;
+ Q_QML_EXPORT bool isString() const;
bool isSymbol() const;
bool isCanonicalNumericIndexString() const;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index d2aa334805..f3351f6da0 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -231,17 +231,17 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
} else if (r.type.isValid()) {
if (lookup) {
if (r.type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
- siinfo->init(e);
- if (siinfo->qobjectApi(e)) {
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) {
+ e->singletonInstance<QObject*>(r.type);
lookup->qmlContextSingletonLookup.singleton =
static_cast<Heap::Object*>(
Value::fromReturnedValue(
QQmlTypeWrapper::create(v4, nullptr, r.type)
).heapObject());
} else {
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
+ QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton));
lookup->qmlContextSingletonLookup.singleton = o->d();
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
@@ -457,11 +457,17 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *
// into the handler expression through the locals of the call context. So for onClicked: { ... }
// the parameters of the clicked signal are injected and we must allow for them to be found here
// before any other property from the QML context.
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- if (ctx.d()->type == Heap::ExecutionContext::Type_CallContext) {
- uint index = ctx.d()->internalClass->indexOfValueOrGetter(name);
- if (index < UINT_MAX)
- return static_cast<Heap::CallContext*>(ctx.d())->locals[index].asReturnedValue();
+ for (Heap::ExecutionContext *ctx = engine->currentContext()->d(); ctx; ctx = ctx->outer) {
+ if (ctx->type == Heap::ExecutionContext::Type_CallContext) {
+ const uint index = ctx->internalClass->indexOfValueOrGetter(name);
+ if (index < std::numeric_limits<uint>::max())
+ return static_cast<Heap::CallContext *>(ctx)->locals[index].asReturnedValue();
+ }
+
+ // Skip only block contexts within the current call context.
+ // Other contexts need a regular QML property lookup. See below.
+ if (ctx->type != Heap::ExecutionContext::Type_BlockContext)
+ break;
}
bool hasProperty = false;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index ba9029bd4d..e81c90dd1a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -560,9 +560,9 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QQmlContextData *callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
- const char *valueType = nullptr;
- if (v.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(v.userType());
+ const char *valueType = (v.userType() == QMetaType::UnknownType)
+ ? "an unknown type"
+ : QMetaType::typeName(v.userType());
const char *targetTypeName = QMetaType::typeName(property->propType());
if (!targetTypeName)
@@ -851,7 +851,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
if (!ddata || !ddata->propertyCache) {
QQmlPropertyData local;
QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local);
- return getProperty(engine, qobj, property);
+ return property ? getProperty(engine, qobj, property) : QV4::Encode::undefined();
}
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 8f2b162106..e95dfa775f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -717,30 +717,6 @@ ReturnedValue Runtime::LoadElement::call(ExecutionEngine *engine, const Value &o
return getElementFallback(engine, object, index);
}
-ReturnedValue Runtime::LoadElement_Traced::call(ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->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->values.size)
- if (!s->data(idx).isEmpty())
- return s->data(idx).asReturnedValue();
- }
- }
- }
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementIntFallback(engine, object, idx);
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementFallback(engine, object, index);
-}
-
static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
@@ -796,30 +772,6 @@ void Runtime::StoreElement::call(ExecutionEngine *engine, const Value &object, c
engine->throwTypeError();
}
-void Runtime::StoreElement_traced::call(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->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->values.size) {
- s->setData(engine, idx, value);
- return;
- }
- }
- }
- }
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict())
- engine->throwTypeError();
-}
-
ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &in, int iterator)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 86cbccde23..13a73b7046 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -154,10 +154,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
{
static void call(ExecutionEngine *, const Value &, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreElement_traced : Method<Throws::Yes>
- {
- static void call(ExecutionEngine *, const Value &, const Value &, const Value &, quint8 *);
- };
struct Q_QML_PRIVATE_EXPORT LoadProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, int);
@@ -170,10 +166,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadElement_Traced : Method<Throws::Yes>
- {
- static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, quint8 *);
- };
struct Q_QML_PRIVATE_EXPORT LoadSuperProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index a84521e205..a5e62d3e35 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -39,11 +39,6 @@
#include "qv4serialize_p.h"
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#include <private/qqmllistmodelworkeragent_p.h>
-#endif
-
#include <private/qv4value_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4regexpobject_p.h>
@@ -85,9 +80,7 @@ enum Type {
WorkerNumber,
WorkerDate,
WorkerRegexp,
-#if QT_CONFIG(qml_list_model)
WorkerListModel,
-#endif
#if QT_CONFIG(qml_sequence_object)
WorkerSequence
#endif
@@ -235,18 +228,15 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
} else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
// XXX TODO: Generalize passing objects between the main thread and worker scripts so
// that others can trivially plug in their elements.
-#if QT_CONFIG(qml_list_model)
- QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
- if (lm && lm->agent()) {
- QQmlListModelWorkerAgent *agent = lm->agent();
- agent->addref();
- push(data, valueheader(WorkerListModel));
- push(data, (void *)agent);
- return;
+ if (QObject *lm = qobjectWrapper->object()) {
+ if (QObject *agent = qvariant_cast<QObject *>(lm->property("agent"))) {
+ if (QMetaObject::invokeMethod(agent, "addref")) {
+ push(data, valueheader(WorkerListModel));
+ push(data, (void *)agent);
+ return;
+ }
+ }
}
-#else
- Q_UNUSED(qobjectWrapper);
-#endif
// No other QObject's are allowed to be sent
push(data, valueheader(WorkerUndefined));
} else if (const Object *o = v.as<Object>()) {
@@ -298,6 +288,41 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
}
}
+struct VariantRef
+{
+ VariantRef() : obj(nullptr) {}
+ VariantRef(const VariantRef &r) : obj(r.obj) { addref(); }
+ VariantRef(QObject *a) : obj(a) { addref(); }
+ ~VariantRef() { release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ o.addref();
+ release();
+ obj = o.obj;
+ return *this;
+ }
+
+ void addref() const
+ {
+ if (obj)
+ QMetaObject::invokeMethod(obj, "addref");
+ }
+
+ void release() const
+ {
+ if (obj)
+ QMetaObject::invokeMethod(obj, "release");
+
+ }
+
+ QObject *obj;
+};
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(VariantRef)
+Q_DECLARE_METATYPE(QV4::ExecutionEngine *)
+QT_BEGIN_NAMESPACE
+
ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
{
quint32 header = popUint32(data);
@@ -366,24 +391,21 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
data += ALIGN(length * sizeof(quint16));
return Encode(engine->newRegExpObject(pattern, flags));
}
-#if QT_CONFIG(qml_list_model)
case WorkerListModel:
{
- void *ptr = popPtr(data);
- QQmlListModelWorkerAgent *agent = (QQmlListModelWorkerAgent *)ptr;
+ QObject *agent = reinterpret_cast<QObject *>(popPtr(data));
QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(engine, agent));
// ### Find a better solution then the ugly property
- QQmlListModelWorkerAgent::VariantRef ref(agent);
+ VariantRef ref(agent);
QVariant var = QVariant::fromValue(ref);
QV4::ScopedValue v(scope, scope.engine->fromVariant(var));
QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref")));
rv->as<Object>()->defineReadonlyProperty(s, v);
- agent->release();
- agent->setEngine(engine);
+ QMetaObject::invokeMethod(agent, "release");
+ agent->setProperty("engine", QVariant::fromValue(engine));
return rv->asReturnedValue();
}
-#endif
#if QT_CONFIG(qml_sequence_object)
case WorkerSequence:
{
@@ -423,4 +445,3 @@ ReturnedValue Serialize::deserialize(const QByteArray &data, ExecutionEngine *en
}
QT_END_NAMESPACE
-
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 98e4f4f7b9..ec44f42933 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -61,7 +61,9 @@
#include "qv4alloca_p.h"
+#if QT_CONFIG(qml_jit)
#include <private/qv4baselinejit_p.h>
+#endif
#undef COUNT_INSTRUCTIONS
@@ -345,85 +347,9 @@ static struct InstrCount {
#undef CHECK_EXCEPTION
#endif
#define CHECK_EXCEPTION \
- if (engine->hasException) \
+ if (engine->hasException || engine->isInterrupted) \
goto handleUnwind
-static inline void traceJumpTakesTruePath(bool truePathTaken, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= truePathTaken ? quint8(ObservedTraceValues::TruePathTaken)
- : quint8(ObservedTraceValues::FalsePathTaken);
-#else
- Q_UNUSED(truePathTaken);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceValue(ReturnedValue acc, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- switch (Primitive::fromReturnedValue(acc).type()) {
- case QV4::Value::Integer_Type:
- *traceInfo |= quint8(ObservedTraceValues::Integer);
- break;
- case QV4::Value::Boolean_Type:
- *traceInfo |= quint8(ObservedTraceValues::Boolean);
- break;
- case QV4::Value::Double_Type:
- *traceInfo |= quint8(ObservedTraceValues::Double);
- break;
- default:
- *traceInfo |= quint8(ObservedTraceValues::Other);
- break;
- }
-#else
- Q_UNUSED(acc);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceIntValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Integer);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceDoubleValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Double);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceOtherValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Other);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
{
Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
@@ -499,22 +425,16 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
if (debugger == nullptr) {
if (function->jittedCode == nullptr) {
- if (engine->canJIT(function)) {
-#if QT_CONFIG(qml_tracing)
- if (function->tracingEnabled())
- runTracingJit(function);
- else
-#endif
- QV4::JIT::BaselineJIT(function).generate();
- } else {
+ if (engine->canJIT(function))
+ QV4::JIT::BaselineJIT(function).generate();
+ else
++function->interpreterCallCount;
- }
}
}
-#endif // V4_ENABLE_JIT
+#endif // QT_CONFIG(qml_jit)
// interpreter
if (debugger)
@@ -523,22 +443,6 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
ReturnedValue result;
if (function->jittedCode != nullptr && debugger == nullptr) {
result = function->jittedCode(frame, engine);
- if (QV4::Value::fromReturnedValue(result).isEmpty()) { // de-optimize!
- if (ShowWhenDeoptimiationHappens) {
- // This is debug code, which is disabled by default, and completely removed by the
- // compiler.
- fprintf(stderr, "*********************** DEOPT! %s ***********************\n"
- "*** deopt IP: %d, line: %d\n",
- function->name()->toQString().toUtf8().constData(),
- frame->instructionPointer,
- frame->lineNumber());
- }
- delete function->codeRef;
- function->codeRef = nullptr;
- function->jittedCode = nullptr;
- function->interpreterCallCount = 0; // reset to restart tracing: apparently we didn't have enough info before
- result = interpret(frame, engine, function->codeData + frame->instructionPointer);
- }
} else {
// interpreter
result = interpret(frame, engine, function->codeData);
@@ -557,11 +461,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
- if (function->tracingEnabled()) {
- for (int i = 0; i < int(function->nFormals); ++i)
- traceValue(frame->jsFrame->argument(i), function, i);
- }
-
MOTH_JUMP_TABLE;
for (;;) {
@@ -620,7 +519,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -633,7 +531,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadScopedLocal)
auto cc = getScope(stack, scope);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -658,7 +555,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
acc = Runtime::LoadName::call(engine, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
@@ -666,7 +562,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->globalGetter(l, engine);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
@@ -674,7 +569,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->qmlContextPropertyGetter(l, engine, nullptr);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameStrict)
@@ -694,25 +588,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- acc = Runtime::LoadElement_Traced::call(engine, STACK_VALUE(base), accumulator, function->traceInfo(traceSlot));
- traceValue(acc, function, traceSlot);
-#else
- Q_UNUSED(traceSlot);
acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
-#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- Runtime::StoreElement_traced::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator, function->traceInfo(traceSlot));
-#else
- Q_UNUSED(traceSlot);
Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
-#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
@@ -721,7 +604,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::LoadProperty::call(engine, accumulator, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
@@ -740,7 +622,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = l->getter(l, engine, accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -814,7 +695,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
Value undef = Value::undefinedValue();
acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
@@ -826,14 +706,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -861,49 +739,42 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
acc = Runtime::CallName::call(engine, name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
STORE_IP();
acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
STORE_IP();
acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
STORE_IP();
acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
STORE_IP();
acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(TailCall)
@@ -1118,7 +989,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = ACC.int_32();
else
takeJump = ACC.toBoolean();
- traceJumpTakesTruePath(takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpTrue)
@@ -1129,7 +999,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = !ACC.int_32();
else
takeJump = !ACC.toBoolean();
- traceJumpTakesTruePath(!takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpFalse)
@@ -1144,6 +1013,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
code += offset;
MOTH_END_INSTR(JumpNotUndefined)
+ MOTH_BEGIN_INSTR(CheckException)
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)
@@ -1289,12 +1162,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UPlus)
- if (Q_LIKELY(ACC.isNumber())) {
- if (ACC.isDouble())
- traceDoubleValue(function, traceSlot);
- else
- traceIntValue(function, traceSlot);
- } else {
+ if (Q_UNLIKELY(!ACC.isNumber())) {
acc = Encode(ACC.toNumberImpl());
CHECK_EXCEPTION;
}
@@ -1305,17 +1173,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
int a = ACC.int_32();
if (a == 0 || a == std::numeric_limits<int>::min()) {
acc = Encode(-static_cast<double>(a));
- traceDoubleValue(function, traceSlot);
} else {
- acc = sub_int32(0, ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(0, ACC.int_32());
}
} else if (ACC.isDouble()) {
acc ^= (1ull << 63); // simply flip sign bit
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(-ACC.toNumberImpl());
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(UMinus)
@@ -1326,57 +1191,49 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Increment)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = add_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = add_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() + 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() + 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = sub_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = sub_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() - 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() - 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = add_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = add_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() + ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Add::call(engine, left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(Sub)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = sub_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() - ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Sub::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Sub)
@@ -1393,15 +1250,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Mul)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = mul_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = mul_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() * ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Mul::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Mul)
@@ -1415,7 +1270,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(BitAnd)
@@ -1513,7 +1367,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(Debug)
handleUnwind:
- Q_ASSERT(engine->hasException || frame->unwindLevel);
+ // We do start the exception handler in case of isInterrupted. The exception handler will
+ // immediately abort, due to the same isInterrupted. We don't skip the exception handler
+ // because the current behavior is easier to implement in the JIT.
+ Q_ASSERT(engine->hasException || engine->isInterrupted || frame->unwindLevel);
if (!frame->unwindHandler) {
acc = Encode::undefined();
return acc;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 4ac7120d36..8a76e60f20 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -58,8 +58,6 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Moth {
-void runTracingJit(QV4::Function *function);
-
class VME
{
public:
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index a4d91640c5..9dda104cd1 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -58,7 +58,7 @@ namespace QV4 {
struct Lookup;
-struct OwnPropertyKeyIterator {
+struct Q_QML_PRIVATE_EXPORT OwnPropertyKeyIterator {
virtual ~OwnPropertyKeyIterator() = 0;
virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0;
};
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index d96a1c285a..ca3282556e 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -70,7 +70,9 @@ include(parser/parser.pri)
include(compiler/compiler.pri)
include(jsapi/jsapi.pri)
include(jsruntime/jsruntime.pri)
-include(jit/jit.pri)
+qtConfig(qml-jit) {
+ include(jit/jit.pri)
+}
include(qml/qml.pri)
include(debugger/debugger.pri)
include(qmldirparser/qmldirparser.pri)
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index 0bb8cb954e..eadba394b4 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -3,6 +3,7 @@ HEADERS += \
$$PWD/qintrusivelist_p.h \
$$PWD/qpodvector_p.h \
$$PWD/qhashedstring_p.h \
+ $$PWD/qprimefornumbits_p.h \
$$PWD/qqmlrefcount_p.h \
$$PWD/qfieldlist_p.h \
$$PWD/qqmlthread_p.h \
@@ -18,8 +19,7 @@ HEADERS += \
SOURCES += \
$$PWD/qintrusivelist.cpp \
$$PWD/qhashedstring.cpp \
- $$PWD/qqmlthread.cpp \
- $$PWD/qstringhash.cpp
+ $$PWD/qqmlthread.cpp
# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
# clock_gettime() is implemented in librt on these systems
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index bb6688599d..7a8fdd0a14 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -41,6 +41,60 @@
QT_BEGIN_NAMESPACE
+// Copy of QString's qMemCompare
+bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *a = (const quint16 *)lhs;
+ const quint16 *b = (const quint16 *)rhs;
+
+ if (a == b || !length)
+ return true;
+
+ union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
+
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
diff --git a/src/qml/types/qqmlmodelsmodule_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h
index 2bb04f1e11..6e9acbf7fd 100644
--- a/src/qml/types/qqmlmodelsmodule_p.h
+++ b/src/qml/qml/ftw/qprimefornumbits_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Research In Motion.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLMODELSMODULE_H
-#define QQMLMODELSMODULE_H
+#ifndef QPRIMEFORNUMBITS_P_H
+#define QPRIMEFORNUMBITS_P_H
//
// W A R N I N G
@@ -55,18 +55,26 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlModelsModule
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The qPrimeForNumBits() function returns the prime associated to a
+ power of two. For example, qPrimeForNumBits(8) returns 257.
+*/
+
+inline int qPrimeForNumBits(int numBits)
{
-public:
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- static void registerQmlTypes();
- static void registerQuickTypes();
-#endif
+ static constexpr const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+ };
- static void defineModule();
- static void defineLabsModule();
-};
+ return (1 << numBits) + prime_deltas[numBits];
+}
QT_END_NAMESPACE
-#endif
+#endif // QPRIMEFORNUMBITS_P_H
diff --git a/src/qml/qml/ftw/qstringhash.cpp b/src/qml/qml/ftw/qstringhash.cpp
deleted file mode 100644
index a483dcb810..0000000000
--- a/src/qml/qml/ftw/qstringhash.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qstringhash_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
-*/
-static const int MinNumBits = 4;
-
-/*
- The prime_deltas array is a table of selected prime values, even
- though it doesn't look like one. The primes we are using are 1,
- 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
- surrounding of a power of two.
-
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-void QStringHashData::rehashToSize(int size)
-{
- short bits = qMax(MinNumBits, (int)numBits);
- while (primeForNumBits(bits) < size) bits++;
-
- if (bits > numBits)
- rehashToBits(bits);
-}
-
-void QStringHashData::rehashToBits(short bits)
-{
- numBits = qMax(MinNumBits, (int)bits);
-
- int nb = primeForNumBits(numBits);
- if (nb == numBuckets && buckets)
- return;
-
- QStringHashNode **newBuckets = new QStringHashNode *[nb];
- ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
-
- // Preserve the existing order within buckets so that items with the
- // same key will retain the same find/findNext order
- for (int i = 0; i < numBuckets; ++i) {
- QStringHashNode *bucket = buckets[i];
- if (bucket)
- rehashNode(newBuckets, nb, bucket);
- }
-
- delete [] buckets;
- buckets = newBuckets;
- numBuckets = nb;
-}
-
-void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
-{
- QStringHashNode *next = node->next.data();
- if (next)
- rehashNode(newBuckets, nb, next);
-
- int bucket = node->hash % nb;
- node->next = newBuckets[bucket];
- newBuckets[bucket] = node;
-}
-
-// Copy of QString's qMemCompare
-bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
-{
- Q_ASSERT(lhs && rhs);
- const quint16 *a = (const quint16 *)lhs;
- const quint16 *b = (const quint16 *)rhs;
-
- if (a == b || !length)
- return true;
-
- union {
- const quint16 *w;
- const quint32 *d;
- quintptr value;
- } sa, sb;
- sa.w = a;
- sb.w = b;
-
- // check alignment
- if ((sa.value & 2) == (sb.value & 2)) {
- // both addresses have the same alignment
- if (sa.value & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*sa.w != *sb.w)
- return false;
- --length;
- ++sa.w;
- ++sb.w;
-
- // now both addresses are 4-bytes aligned
- }
-
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *e = sa.d + (length >> 1);
- for ( ; sa.d != e; ++sa.d, ++sb.d) {
- if (*sa.d != *sb.d)
- return false;
- }
-
- // do we have a tail?
- return (length & 1) ? *sa.w == *sb.w : true;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const quint16 *e = sa.w + length;
- for ( ; sa.w != e; ++sa.w, ++sb.w) {
- if (*sa.w != *sb.w)
- return false;
- }
- }
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
index c7251e8837..f9435b4919 100644
--- a/src/qml/qml/ftw/qstringhash_p.h
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -52,11 +52,14 @@
//
#include <private/qhashedstring_p.h>
+#include <private/qprimefornumbits_p.h>
+
+#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
class QStringHashData;
-class Q_AUTOTEST_EXPORT QStringHashNode
+class QStringHashNode
{
public:
QStringHashNode()
@@ -154,12 +157,20 @@ public:
}
};
-class Q_AUTOTEST_EXPORT QStringHashData
+class QStringHashData
{
+ Q_DISABLE_COPY_MOVE(QStringHashData)
public:
- QStringHashData() {}
+ QStringHashData() = default;
+ ~QStringHashData() = default;
+
+ /*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+ */
+ enum { MinNumBits = 4 };
- QStringHashNode **buckets = nullptr;
+ QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash
int numBuckets = 0;
int size = 0;
short numBits = 0;
@@ -174,13 +185,51 @@ public:
QStringHashNode *n;
StringHash *p;
};
- void rehashToBits(short);
- void rehashToSize(int);
- void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
-private:
- QStringHashData(const QStringHashData &);
- QStringHashData &operator=(const QStringHashData &);
+ void rehashToBits(short bits)
+ {
+ numBits = qMax(short(MinNumBits), bits);
+
+ int nb = qPrimeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ QStringHashNode **newBuckets = new QStringHashNode *[nb];
+ ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
+
+ // Preserve the existing order within buckets so that items with the
+ // same key will retain the same find/findNext order
+ for (int i = 0; i < numBuckets; ++i) {
+ QStringHashNode *bucket = buckets[i];
+ if (bucket)
+ rehashNode(newBuckets, nb, bucket);
+ }
+
+ delete [] buckets;
+ buckets = newBuckets;
+ numBuckets = nb;
+ }
+
+ void rehashToSize(int size)
+ {
+ short bits = qMax(short(MinNumBits), numBits);
+ while (qPrimeForNumBits(bits) < size)
+ bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits);
+ }
+
+ void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
+ {
+ QStringHashNode *next = node->next.data();
+ if (next)
+ rehashNode(newBuckets, nb, next);
+
+ int bucket = node->hash % nb;
+ node->next = newBuckets[bucket];
+ newBuckets[bucket] = node;
+ }
};
// For a supplied key type, in what form do we need to keep a hashed version?
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 3000f56601..7b3f89e943 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -579,9 +579,15 @@ namespace QtQml {
Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *,
- const QMetaObject *, bool create);
+#if QT_DEPRECATED_SINCE(5, 14)
+ Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+ Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObject(
+ int *, const QObject *, const QMetaObject *, bool create);
+#endif
+ Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
+ const QMetaObject *);
+ Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
+ bool create = true);
#ifndef Q_QDOC
}
@@ -602,8 +608,9 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
- static int idx = -1;
- return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
+ QObject *mutableObj = const_cast<QObject *>(obj);
+ return qmlAttachedPropertiesObject(
+ mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create);
}
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index b164517011..656c7dd515 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -517,9 +517,9 @@ QString QQmlBinding::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- quint16 lineNumber = f->compiledFunction->location.line;
- quint16 columnNumber = f->compiledFunction->location.column;
- return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber));
+ uint lineNumber = f->compiledFunction->location.line;
+ uint columnNumber = f->compiledFunction->location.column;
+ return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
return QStringLiteral("[native code]");
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 2468de6857..f4c03fc17c 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -57,6 +57,7 @@
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
#include <private/qqmlrefcount_p.h>
+#include <qqmlprivate.h>
#include <qjsengine.h>
#include <qvector.h>
@@ -265,7 +266,7 @@ public:
}
bool hasExtendedData() const { return extendedData != nullptr; }
- QHash<int, QObject *> *attachedProperties() const;
+ QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const;
static inline bool wasDeleted(const QObject *);
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index f070f16afd..bb2b3e462c 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1057,7 +1057,7 @@ QQmlEngine::~QQmlEngine()
// XXX TODO: performance -- store list of singleton types separately?
QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
for (const QQmlType &currType : singletonTypes)
- currType.singletonInstanceInfo()->destroy(this);
+ d->destroySingletonInstance(currType);
delete d->rootContext;
d->rootContext = nullptr;
@@ -1402,23 +1402,13 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
+ Q_D(QQmlEngine);
QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
- QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo();
- info->init(this);
-
- if (QObject* o = info->qobjectApi(this))
- return this->newQObject(o);
- else {
- QJSValue value = info->scriptApi(this);
- if (!value.isUndefined())
- return value;
- }
-
- return QJSValue();
+ return d->singletonInstance<QJSValue>(type);
}
/*!
@@ -1617,29 +1607,39 @@ QQmlEngine *qmlEngine(const QObject *obj)
return data->context->engine;
}
-QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
+ QObject *object, bool create)
{
- QQmlData *data = QQmlData::get(object, create);
- if (!data)
- return nullptr; // Attached properties are only on objects created by QML, unless explicitly requested (create==true)
+ if (!pf)
+ return nullptr;
- QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
+ QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
if (rv || !create)
return rv;
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
- QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(engine, id);
- if (!pf)
- return nullptr;
-
- rv = pf(const_cast<QObject *>(object));
+ rv = pf(object);
if (rv)
- data->attachedProperties()->insert(id, rv);
+ data->attachedProperties()->insert(pf, rv);
return rv;
}
+#if QT_DEPRECATED_SINCE(5, 14)
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+{
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
+ return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data,
+ const_cast<QObject *>(object), create);
+}
+
QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
const QMetaObject *attachedMetaObject, bool create)
{
@@ -1653,6 +1653,30 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
return qmlAttachedPropertiesObjectById(*idCache, object, create);
}
+#endif
+
+QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
+ const QMetaObject *attachedMetaObject)
+{
+ QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
+ return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
+ attachedMetaObject);
+}
+
+QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
+{
+ if (!object)
+ return nullptr;
+
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ return resolveAttachedProperties(func, data, object, create);
+}
} // namespace QtQml
@@ -1694,7 +1718,7 @@ public:
QQmlDataExtended();
~QQmlDataExtended();
- QHash<int, QObject *> attachedProperties;
+ QHash<QQmlAttachedPropertiesFunc, QObject *> attachedProperties;
};
QQmlDataExtended::QQmlDataExtended()
@@ -1840,7 +1864,7 @@ void QQmlData::disconnectNotifiers()
}
}
-QHash<int, QObject *> *QQmlData::attachedProperties() const
+QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties() const
{
if (!extendedData) extendedData = new QQmlDataExtended;
return &extendedData->attachedProperties;
@@ -2413,6 +2437,67 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::Compi
m_compositeTypes.remove(compilationUnit->metaTypeId);
}
+template<>
+QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
+{
+ Q_Q(QQmlEngine);
+
+ QJSValue value = singletonInstances.value(type);
+ if (!value.isUndefined()) {
+ return value;
+ }
+
+ QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ Q_ASSERT(siinfo != nullptr);
+
+ if (siinfo->scriptCallback) {
+ value = siinfo->scriptCallback(q, q);
+ if (value.isQObject()) {
+ QObject *o = value.toQObject();
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ }
+ singletonInstances.insert(type, value);
+
+ } else if (siinfo->qobjectCallback) {
+ QObject *o = siinfo->qobjectCallback(q, q);
+ if (!o) {
+ qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
+ qPrintable(QString::fromUtf8(type.typeName())));
+ }
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(q, o);
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+
+ } else if (!siinfo->url.isEmpty()) {
+ QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ QObject *o = component.beginCreate(q->rootContext());
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+ component.completeCreate();
+ }
+
+ return value;
+}
+
+void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+{
+ Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+
+ QObject* o = singletonInstances.take(type).toQObject();
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
+ return;
+ delete o;
+ }
+}
+
bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
return typeLoader.isTypeLoaded(url);
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 871e6bd9b4..da91c8fa15 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -175,12 +175,7 @@ Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId);
template<typename T>
T QQmlEngine::singletonInstance(int qmlTypeId) {
- QJSValue instance = singletonInstance<QJSValue>(qmlTypeId);
- if (!instance.isQObject())
- return nullptr;
-
- QObject *object = instance.toQObject();
- return qobject_cast<T>(object);
+ return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index dab4e54cd6..4f7fb79593 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -229,6 +229,10 @@ public:
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
+ template <typename T>
+ T singletonInstance(const QQmlType &type);
+ void destroySingletonInstance(const QQmlType &type);
+
void sendQuit();
void sendExit(int retCode = 0);
void warning(const QQmlError &);
@@ -262,6 +266,8 @@ public:
mutable QMutex networkAccessManagerMutex;
private:
+ QHash<QQmlType, QJSValue> singletonInstances;
+
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
// the threaded loader. Only access them through their respective accessor methods.
QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
@@ -437,6 +443,14 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
return get(qmlEngine);
}
+template<>
+Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
+
+template<typename T>
+T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
+ return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_P_H
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 453c8ab8a8..92f2ccbb4a 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -182,7 +182,7 @@ private:
QV4::Function *m_v4Function;
};
-class QQmlPropertyCapture
+class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture
{
public:
QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w)
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 32f281b4f2..09df23de51 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -76,6 +76,8 @@ public:
const QQmlMetaTypeData *operator->() const { return data; }
operator const QQmlMetaTypeData *() const { return data; }
+ bool isValid() const { return data != nullptr; }
+
private:
QMutexLocker locker;
LockedData *data = nullptr;
@@ -143,12 +145,6 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->baseMetaObject = type.metaObject;
d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
- if (d->extraData.cd->attachedPropertiesType) {
- d->extraData.cd->attachedPropertiesId = data->attachedPropertyId(d->baseMetaObject,
- d->index);
- } else {
- d->extraData.cd->attachedPropertiesId = -1;
- }
d->extraData.cd->parserStatusCast = type.parserStatusCast;
d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
@@ -599,19 +595,6 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
data->undeletableTypes.insert(dtype);
}
-int QQmlMetaType::registerAttachedPropertyId(const QMetaObject *metaObject, int index)
-{
- QQmlMetaTypeDataPtr data;
- return data->attachedPropertyId(metaObject, index);
-}
-
-bool QQmlMetaType::unregisterAttachedPropertyId(const QMetaObject *metaObject, int index)
-{
- QQmlMetaTypeDataPtr data;
- // This is run from the QQmlType dtor. QQmlTypes in user code can outlive QQmlMetaTypeData.
- return data ? data->removeAttachedPropertyId(metaObject, index) : false;
-}
-
static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
int majorVersion)
{
@@ -916,6 +899,7 @@ int QQmlMetaType::listType(int id)
return 0;
}
+#if QT_DEPRECATED_SINCE(5, 14)
int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
{
QQmlMetaTypeDataPtr data;
@@ -937,6 +921,16 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr
QQmlMetaTypeDataPtr data;
return data->types.at(id).attachedPropertiesFunction(engine);
}
+#endif
+
+QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
+ const QMetaObject *mo)
+{
+ QQmlMetaTypeDataPtr data;
+
+ QQmlType type(data->metaObjectToType.value(mo));
+ return type.attachedPropertiesFunction(engine);
+}
QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
{
@@ -1216,6 +1210,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
{
QQmlMetaTypeDataPtr data;
+ // in case this is being called during program exit, `data` might be destructed already
+ if (!data.isValid())
+ return;
+
bool deletedAtLeastOneType;
do {
deletedAtLeastOneType = false;
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index dde9cf68d7..9af982d1c3 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -88,9 +88,6 @@ public:
static void registerUndeletableType(const QQmlType &dtype);
- static int registerAttachedPropertyId(const QMetaObject *metaObject, int index);
- static bool unregisterAttachedPropertyId(const QMetaObject *metaObject, int index);
-
static QList<QString> qmlTypeNames();
static QList<QQmlType> qmlTypes();
static QList<QQmlType> qmlSingletonTypes();
@@ -122,8 +119,14 @@ public:
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
static int listType(int);
- static int attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *);
- static QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *, int);
+#if QT_DEPRECATED_SINCE(5, 14)
+ static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine,
+ const QMetaObject *);
+ static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *,
+ int);
+#endif
+ static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
+ const QMetaObject *);
enum TypeCategory { Unknown, Object, List };
static TypeCategory typeCategory(int);
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index c45bc16280..5239b635ce 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -134,27 +134,8 @@ struct QQmlMetaTypeData
qWarning("%s", message.toUtf8().constData());
}
- int attachedPropertyId(const QMetaObject *metaObject, int ownIndex)
- {
- auto iter = attachedPropertyIds.find(metaObject);
- return (iter == attachedPropertyIds.end())
- ? *attachedPropertyIds.insert(metaObject, ownIndex)
- : *iter;
- }
-
- bool removeAttachedPropertyId(const QMetaObject *metaObject, int ownIndex)
- {
- auto iter = attachedPropertyIds.find(metaObject);
- if (iter != attachedPropertyIds.end() && *iter == ownIndex) {
- attachedPropertyIds.erase(iter);
- return true;
- }
- return false;
- }
-
private:
QStringList *m_typeRegistrationFailures = nullptr;
- QHash<const QMetaObject *, int> attachedPropertyIds;
};
inline uint qHash(const QQmlMetaTypeData::VersionedUri &v)
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index c36b3ed386..26d3b5b6c1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -824,8 +824,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
else
return false;
}
- const int id = attachedType.attachedPropertiesId(QQmlEnginePrivate::get(engine));
- QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
+ QObject *qmlObject = qmlAttachedPropertiesObject(
+ _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
return false;
return true;
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index c0232a7691..fa05b3fe19 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -77,6 +77,11 @@ typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *)
typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
+inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
+{
+ return qHash(quintptr(func), seed);
+}
+
template <typename TYPE>
class QQmlTypeInfo
{
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 000b88ebaa..c8166695ba 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -277,7 +277,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.importNamespace) {
if ((ii + 1) == path.count()) return; // No type following the namespace
@@ -289,7 +289,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.scriptIndex != -1) {
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 88eedec061..926e2810d5 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -51,70 +51,6 @@
QT_BEGIN_NAMESPACE
-void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
-{
- if (scriptCallback && scriptApi(e).isUndefined()) {
- QJSValue value = scriptCallback(e, e);
- if (value.isQObject()) {
- QObject *o = value.toQObject();
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- }
- setScriptApi(e, value);
- } else if (qobjectCallback && !qobjectApi(e)) {
- QObject *o = qobjectCallback(e, e);
- setQObjectApi(e, o);
- if (!o) {
- qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName));
- }
- // if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(e, o);
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- } else if (!url.isEmpty() && !qobjectApi(e)) {
- QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
- QObject *o = component.beginCreate(e->rootContext());
- setQObjectApi(e, o);
- if (o)
- component.completeCreate();
- }
-}
-
-void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
-{
- // cleans up the engine-specific singleton instances if they exist.
- scriptApis.remove(e);
- QObject *o = qobjectApis.take(e);
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
- return;
- delete o;
- }
-}
-
-void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
-{
- qobjectApis.insert(e, o);
-}
-
-QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
-{
- return qobjectApis.value(e);
-}
-
-void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v)
-{
- scriptApis.insert(e, v);
-}
-
-QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
-{
- return scriptApis.value(e);
-}
-
QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
: regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
containsRevisionedAttributes(false), baseMetaObject(nullptr),
@@ -156,10 +92,6 @@ QQmlTypePrivate::~QQmlTypePrivate()
qDeleteAll(scopedEnums);
switch (regType) {
case QQmlType::CppType:
- // If attached properties were successfully registered, deregister them.
- // (They may not have been registered if some other type used the same baseMetaObject)
- if (extraData.cd->attachedPropertiesType)
- QQmlMetaType::unregisterAttachedPropertyId(baseMetaObject, index);
delete extraData.cd->customParser;
delete extraData.cd;
break;
@@ -640,6 +572,16 @@ bool QQmlType::isCompositeSingleton() const
return d && d->regType == CompositeSingletonType;
}
+bool QQmlType::isQObjectSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
+}
+
+bool QQmlType::isQJSValueSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
+}
+
int QQmlType::typeId() const
{
return d ? d->typeId : -1;
@@ -708,6 +650,7 @@ const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) c
return base.attachedPropertiesType(engine);
}
+#if QT_DEPRECATED_SINCE(5, 14)
/*
This is the id passed to qmlAttachedPropertiesById(). This is different from the index
for the case that a single class is registered under two or more names (eg. Item in
@@ -718,13 +661,14 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
if (!d)
return -1;
if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesId;
+ return d->extraData.cd->attachedPropertiesType ? d->index : -1;
QQmlType base;
if (d->regType == CompositeType)
base = resolveCompositeBaseType(engine);
return base.attachedPropertiesId(engine);
}
+#endif
int QQmlType::parserStatusCast() const
{
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index 0e59b1be06..1d65a08c8f 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -118,6 +118,8 @@ public:
bool isInterface() const;
bool isComposite() const;
bool isCompositeSingleton() const;
+ bool isQObjectSingleton() const;
+ bool isQJSValueSingleton() const;
int typeId() const;
int qListTypeId() const;
@@ -129,7 +131,9 @@ public:
QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
- int attachedPropertiesId(QQmlEnginePrivate *engine) const;
+#if QT_DEPRECATED_SINCE(5, 14)
+ QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const;
+#endif
int parserStatusCast() const;
const char *interfaceIId() const;
@@ -138,28 +142,13 @@ public:
int index() const;
- class Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
{
- public:
- SingletonInstanceInfo()
- : scriptCallback(nullptr), qobjectCallback(nullptr), instanceMetaObject(nullptr) {}
-
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject;
+ QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ const QMetaObject *instanceMetaObject = nullptr;
QString typeName;
QUrl url; // used by composite singletons
-
- void setQObjectApi(QQmlEngine *, QObject *);
- QObject *qobjectApi(QQmlEngine *) const;
- void setScriptApi(QQmlEngine *, const QJSValue &);
- QJSValue scriptApi(QQmlEngine *) const;
-
- void init(QQmlEngine *);
- void destroy(QQmlEngine *);
-
- QHash<QQmlEngine *, QJSValue> scriptApis;
- QHash<QQmlEngine *, QObject *> qobjectApis;
};
SingletonInstanceInfo *singletonInstanceInfo() const;
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index b317aff740..d381e11df4 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -83,7 +83,6 @@ public:
QQmlCustomParser *customParser;
QQmlAttachedPropertiesFunc attachedPropertiesFunc;
const QMetaObject *attachedPropertiesType;
- int attachedPropertiesId;
int propertyValueSourceCast;
int propertyValueInterceptorCast;
bool registerEnumClassesUnscoped;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 86513b5ff8..236daac75c 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -89,25 +89,21 @@ QObject* QQmlTypeWrapper::singletonObject() const
if (!isSingleton())
return nullptr;
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- return siinfo->qobjectApi(e);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ return e->singletonInstance<QObject*>(d()->type());
}
QVariant QQmlTypeWrapper::toVariant() const
{
- // Only Singleton type wrappers can be converted to a variant.
if (!isSingleton())
- return QVariant();
+ return QVariant::fromValue<QObject *>(d()->object);
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
- return QVariant::fromValue<QObject*>(qobjectSingleton);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ const QQmlType type = d()->type();
+ if (type.isQJSValueSingleton())
+ return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
- return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e));
+ return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
@@ -195,50 +191,51 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// singleton types are handled differently to other types.
if (type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- // check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (includeEnums && name->startsWithUpper()) {
- bool ok = false;
- int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return QV4::Value::fromInt32(value).asReturnedValue();
-
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
- if (ok) {
- Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
- enumWrapper->d()->typePrivate = type.priv();
- QQmlType::refHandle(enumWrapper->d()->typePrivate);
- enumWrapper->d()->scopeEnumIndex = value;
- return enumWrapper.asReturnedValue();
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ QJSValue scriptSingleton;
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ // check for enum value
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (includeEnums && name->startsWithUpper()) {
+ bool ok = false;
+ int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return QV4::Value::fromInt32(value).asReturnedValue();
+
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+ return enumWrapper.asReturnedValue();
+ }
}
- }
- // check for property.
- bool ok;
- const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
- if (hasProperty)
- *hasProperty = ok;
-
- // Warn when attempting to access a lowercased enum value, singleton case
- if (!ok && includeEnums && !name->startsWithUpper()) {
- enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return throwLowercaseEnumError(v4, name, type);
- }
+ // check for property.
+ bool ok;
+ const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
+ if (hasProperty)
+ *hasProperty = ok;
+
+ // Warn when attempting to access a lowercased enum value, singleton case
+ if (!ok && includeEnums && !name->startsWithUpper()) {
+ enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return throwLowercaseEnumError(v4, name, type);
+ }
- return result;
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
- if (!!o)
- return o->get(name);
+ return result;
+ }
+ } else if (type.isQJSValueSingleton()) {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
+ if (!!o)
+ return o->get(name);
+ }
}
// Fall through to base implementation
@@ -263,7 +260,9 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
} else if (w->d()->object) {
- QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object);
+ QObject *ao = qmlAttachedPropertiesObject(
+ object,
+ type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
if (ao)
return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
@@ -335,26 +334,28 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
if (type.isValid() && !type.isSingleton() && w->d()->object) {
QObject *object = w->d()->object;
QQmlEngine *e = scope.engine->qmlEngine();
- QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object);
+ QObject *ao = qmlAttachedPropertiesObject(
+ object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
if (ao)
return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
return false;
} else if (type.isSingleton()) {
- QQmlEngine *e = scope.engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, siinfo->scriptApi(e)));
- if (!apiprivate) {
- QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
- scope.engine->throwError(error);
- return false;
- } else {
- return apiprivate->put(name, value);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
+ return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+
+ } else {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ if (!apiprivate) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
+ scope.engine->throwError(error);
+ return false;
+ } else {
+ return apiprivate->put(name, value);
+ }
}
}
}
@@ -446,27 +447,25 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (type.isValid()) {
if (type.isSingleton()) {
- QQmlEngine *e = engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (!includeEnums || !name->startsWithUpper()) {
- QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
- if (ddata && ddata->propertyCache) {
- ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
- if (property) {
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
- return lookup->getter(lookup, engine, *This);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (!includeEnums || !name->startsWithUpper()) {
+ QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
+ if (ddata && ddata->propertyCache) {
+ ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ if (property) {
+ lookup->qobjectLookup.ic = This->internalClass();
+ lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *This);
+ }
+ // Fall through to base implementation
}
// Fall through to base implementation
}
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 090b830b3c..a111f72e81 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -53,7 +53,7 @@
#else
# define QT_FEATURE_qml_debug -1
# define QT_FEATURE_qml_sequence_object 1
-# define QT_FEATURE_qml_tracing -1
+# define QT_FEATURE_qml_jit -1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmldelegatecomponent.cpp b/src/qml/types/qqmldelegatecomponent.cpp
deleted file mode 100644
index 470f6cab6a..0000000000
--- a/src/qml/types/qqmldelegatecomponent.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldelegatecomponent_p.h"
-#include <QtQml/private/qqmladaptormodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
- : QQmlComponent(parent)
-{
-}
-
-QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
-{
-}
-
-QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
-{
- if (!adaptorModel)
- return QVariant();
- return adaptorModel->value(adaptorModel->indexAt(row, column), role);
-}
-
-/*!
- \qmlmodule Qt.labs.qmlmodels 1.0
- \title Qt Labs QML Models - QML Types
- \ingroup qmlmodules
- \brief The Qt Labs QML Models module provides various model-related types for use with views.
-
- To use this module, import the module with the following line:
-
- \qml
- import Qt.labs.qmlmodels 1.0
- \endqml
-*/
-
-/*!
- \qmltype DelegateChoice
- \instantiates QQmlDelegateChoice
- \inqmlmodule Qt.labs.qmlmodels
- \brief Encapsulates a delegate and when to use it.
-
- The DelegateChoice type wraps a delegate and defines the circumstances
- in which it should be chosen.
-
- DelegateChoices can be nested inside a DelegateChooser.
-
- \sa DelegateChooser
-*/
-
-/*!
- \qmlproperty string QtQml.Models::DelegateChoice::roleValue
- This property holds the value used to match the role data for the role provided by \l DelegateChooser::role.
-*/
-QVariant QQmlDelegateChoice::roleValue() const
-{
- return m_value;
-}
-
-void QQmlDelegateChoice::setRoleValue(const QVariant &value)
-{
- if (m_value == value)
- return;
- m_value = value;
- emit roleValueChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::row
- This property holds the value used to match the row value of model elements.
- With models that have only the index property (and thus only one column), this property
- should be intended as an index, and set to the desired index value.
-
- \note Setting both row and index has undefined behavior. The two are equivalent and only
- one should be used.
-
- \sa index
-*/
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::index
- This property holds the value used to match the index value of model elements.
- This is effectively an alias for \l row.
-
- \sa row
-*/
-int QQmlDelegateChoice::row() const
-{
- return m_row;
-}
-
-void QQmlDelegateChoice::setRow(int r)
-{
- if (m_row == r)
- return;
- m_row = r;
- emit rowChanged();
- emit indexChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::column
- This property holds the value used to match the column value of model elements.
-*/
-int QQmlDelegateChoice::column() const
-{
- return m_column;
-}
-
-void QQmlDelegateChoice::setColumn(int c)
-{
- if (m_column == c)
- return;
- m_column = c;
- emit columnChanged();
- emit changed();
-}
-
-QQmlComponent *QQmlDelegateChoice::delegate() const
-{
- return m_delegate;
-}
-
-/*!
- \qmlproperty Component QtQml.Models::DelegateChoice::delegate
- This property holds the delegate to use if this choice matches the model item.
-*/
-void QQmlDelegateChoice::setDelegate(QQmlComponent *delegate)
-{
- if (m_delegate == delegate)
- return;
- QQmlAbstractDelegateComponent *adc = static_cast<QQmlAbstractDelegateComponent *>(m_delegate);
- if (adc)
- disconnect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- m_delegate = delegate;
- adc = static_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc)
- connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- emit delegateChanged();
- emit changed();
-}
-
-bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
-{
- if (!m_value.isValid() && m_row < 0 && m_column < 0)
- return true;
-
- const bool roleMatched = (m_value.isValid()) ? value == m_value : true;
- const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
- const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
- return roleMatched && rowMatched && columnMatched;
-}
-
-/*!
- \qmltype DelegateChooser
- \instantiates QQmlDelegateChooser
- \inqmlmodule Qt.labs.qmlmodels
- \brief Allows a view to use different delegates for different types of items in the model.
-
- The DelegateChooser is a special \l Component type intended for those scenarios where a Component is required
- by a view and used as a delegate.
- DelegateChooser encapsulates a set of \l {DelegateChoice}s.
- These choices are used determine the delegate that will be instantiated for each
- item in the model.
- The selection of the choice is performed based on the value that a model item has for \l role,
- and also based on index.
-
- \note This type is intended to transparently work only with TableView and any DelegateModel-based view.
- Views (including user-defined views) that aren't internally based on a DelegateModel need to explicitly support
- this type of component to make it function as described.
-
- \sa DelegateChoice
-*/
-
-/*!
- \qmlproperty string QtQml.Models::DelegateChooser::role
- This property holds the role used to determine the delegate for a given model item.
-
- \sa DelegateChoice
-*/
-void QQmlDelegateChooser::setRole(const QString &role)
-{
- if (m_role == role)
- return;
- m_role = role;
- emit roleChanged();
-}
-
-/*!
- \qmlproperty list<DelegateChoice> QtQml.Models::DelegateChooser::choices
- \default
-
- The list of DelegateChoices for the chooser.
-
- The list is treated as an ordered list, where the first DelegateChoice to match
- will be used be a view.
-
- It should not generally be necessary to refer to the \c choices property,
- as it is the default property for DelegateChooser and thus all child items are
- automatically assigned to this property.
-*/
-
-QQmlListProperty<QQmlDelegateChoice> QQmlDelegateChooser::choices()
-{
- return QQmlListProperty<QQmlDelegateChoice>(this, nullptr,
- QQmlDelegateChooser::choices_append,
- QQmlDelegateChooser::choices_count,
- QQmlDelegateChooser::choices_at,
- QQmlDelegateChooser::choices_clear);
-}
-
-void QQmlDelegateChooser::choices_append(QQmlListProperty<QQmlDelegateChoice> *prop, QQmlDelegateChoice *choice)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- q->m_choices.append(choice);
- connect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->delegateChanged();
-}
-
-int QQmlDelegateChooser::choices_count(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.count();
-}
-
-QQmlDelegateChoice *QQmlDelegateChooser::choices_at(QQmlListProperty<QQmlDelegateChoice> *prop, int index)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.at(index);
-}
-
-void QQmlDelegateChooser::choices_clear(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- for (QQmlDelegateChoice *choice : q->m_choices)
- disconnect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->m_choices.clear();
- q->delegateChanged();
-}
-
-QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const
-{
- QVariant v;
- if (!m_role.isNull())
- v = value(adaptorModel, row, column, m_role);
- if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
- v = value(adaptorModel, row, column, QStringLiteral("modelData"));
- if (v.isValid())
- v = v.toMap().value(m_role);
- }
- // loop through choices, finding first one that fits
- for (int i = 0; i < m_choices.count(); ++i) {
- const QQmlDelegateChoice *choice = m_choices.at(i);
- if (choice->match(row, column, v))
- return choice->delegate();
- }
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmldelegatecomponent_p.h b/src/qml/types/qqmldelegatecomponent_p.h
deleted file mode 100644
index c925ed9a60..0000000000
--- a/src/qml/types/qqmldelegatecomponent_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDELEGATECOMPONENT_P_H
-#define QQMLDELEGATECOMPONENT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <qqmlcomponent.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-// TODO: consider making QQmlAbstractDelegateComponent public API
-class QQmlAbstractDelegateComponentPrivate;
-class QQmlAdaptorModel;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
-{
- Q_OBJECT
-public:
- QQmlAbstractDelegateComponent(QObject *parent = nullptr);
- ~QQmlAbstractDelegateComponent() override;
-
- virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
-
-signals:
- void delegateChanged();
-
-protected:
- QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
-
-private:
- Q_DECLARE_PRIVATE(QQmlAbstractDelegateComponent)
- Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
- Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged)
- Q_PROPERTY(int index READ row WRITE setRow NOTIFY indexChanged)
- Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
- Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
-public:
- QVariant roleValue() const;
- void setRoleValue(const QVariant &roleValue);
-
- int row() const;
- void setRow(int r);
-
- int column() const;
- void setColumn(int c);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *delegate);
-
- virtual bool match(int row, int column, const QVariant &value) const;
-
-signals:
- void roleValueChanged();
- void rowChanged();
- void indexChanged();
- void columnChanged();
- void delegateChanged();
- void changed();
-
-private:
- QVariant m_value;
- int m_row = -1;
- int m_column = -1;
- QQmlComponent *m_delegate = nullptr;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
-{
- Q_OBJECT
- Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
- Q_PROPERTY(QQmlListProperty<QQmlDelegateChoice> choices READ choices CONSTANT)
- Q_CLASSINFO("DefaultProperty", "choices")
-
-public:
- QString role() const { return m_role; }
- void setRole(const QString &role);
-
- virtual QQmlListProperty<QQmlDelegateChoice> choices();
- static void choices_append(QQmlListProperty<QQmlDelegateChoice> *, QQmlDelegateChoice *);
- static int choices_count(QQmlListProperty<QQmlDelegateChoice> *);
- static QQmlDelegateChoice *choices_at(QQmlListProperty<QQmlDelegateChoice> *, int);
- static void choices_clear(QQmlListProperty<QQmlDelegateChoice> *);
-
- QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = -1) const override;
-
-signals:
- void roleChanged();
-
-private:
- QString m_role;
- QList<QQmlDelegateChoice *> m_choices;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlDelegateChoice)
-QML_DECLARE_TYPE(QQmlDelegateChooser)
-
-#endif // QQMLDELEGATECOMPONENT_P_H
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
deleted file mode 100644
index 0e57119368..0000000000
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ /dev/null
@@ -1,3540 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldelegatemodel_p_p.h"
-#include "qqmldelegatecomponent_p.h"
-
-#include <QtQml/qqmlinfo.h>
-
-#include <private/qquickpackage_p.h>
-#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmladaptormodel_p.h>
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlcomponent_p.h>
-#include <private/qqmlincubator_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-#include <qv4objectiterator_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlDelegateModelItem;
-
-namespace QV4 {
-
-namespace Heap {
-
-struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
-
- QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
- uint flag;
-};
-
-struct QQmlDelegateModelGroupChange : Object {
- void init() { Object::init(); }
-
- QQmlChangeSet::ChangeData change;
-};
-
-struct QQmlDelegateModelGroupChangeArray : Object {
- void init(const QVector<QQmlChangeSet::Change> &changes);
- void destroy() {
- delete changes;
- Object::destroy();
- }
-
- QVector<QQmlChangeSet::Change> *changes;
-};
-
-
-}
-
-struct DelegateModelGroupFunction : QV4::FunctionObject
-{
- V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
-
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
- {
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
- }
-
- static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
- {
- QV4::Scope scope(that->engine());
- QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that));
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject);
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- QV4::ScopedValue v(scope, argc ? argv[0] : Value::undefinedValue());
- return f->d()->code(o->d()->item, f->d()->flag, v);
- }
-};
-
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
-{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
- this->flag = flag;
- this->code = code;
-}
-
-}
-
-DEFINE_OBJECT_VTABLE(QV4::DelegateModelGroupFunction);
-
-
-
-class QQmlDelegateModelEngineData : public QV8Engine::Deletable
-{
-public:
- QQmlDelegateModelEngineData(QV4::ExecutionEngine *v4);
- ~QQmlDelegateModelEngineData();
-
- QV4::ReturnedValue array(QV4::ExecutionEngine *engine,
- const QVector<QQmlChangeSet::Change> &changes);
-
- QV4::PersistentValue changeProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, engineData)
-
-
-void QQmlDelegateModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
-{
- prop.setWritable(false);
-}
-
-QVariant QQmlDelegateModelPartsMetaObject::initialValue(int id)
-{
- QQmlDelegateModelParts *parts = static_cast<QQmlDelegateModelParts *>(object());
- QQmlPartsModel *m = new QQmlPartsModel(
- parts->model, QString::fromUtf8(name(id)), parts);
- parts->models.append(m);
- return QVariant::fromValue(static_cast<QObject *>(m));
-}
-
-QQmlDelegateModelParts::QQmlDelegateModelParts(QQmlDelegateModel *parent)
-: QObject(parent), model(parent)
-{
- new QQmlDelegateModelPartsMetaObject(this);
-}
-
-//---------------------------------------------------------------------------
-
-/*!
- \qmltype DelegateModel
- \instantiates QQmlDelegateModel
- \inqmlmodule QtQml.Models
- \brief Encapsulates a model and delegate.
-
- The DelegateModel type encapsulates a model and the delegate that will
- be instantiated for items in the model.
-
- It is usually not necessary to create a DelegateModel.
- However, it can be useful for manipulating and accessing the \l modelIndex
- when a QAbstractItemModel subclass is used as the
- model. Also, DelegateModel is used together with \l Package to
- provide delegates to multiple views, and with DelegateModelGroup to sort and filter
- delegate items.
-
- The example below illustrates using a DelegateModel with a ListView.
-
- \snippet delegatemodel/delegatemodel.qml 0
-*/
-
-QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt)
- : m_delegateChooser(nullptr)
- , m_cacheMetaType(nullptr)
- , m_context(ctxt)
- , m_parts(nullptr)
- , m_filterGroup(QStringLiteral("items"))
- , m_count(0)
- , m_groupCount(Compositor::MinimumGroupCount)
- , m_compositorGroup(Compositor::Cache)
- , m_complete(false)
- , m_delegateValidated(false)
- , m_reset(false)
- , m_transaction(false)
- , m_incubatorCleanupScheduled(false)
- , m_waitingToFetchMore(false)
- , m_cacheItems(nullptr)
- , m_items(nullptr)
- , m_persistedItems(nullptr)
-{
-}
-
-QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate()
-{
- qDeleteAll(m_finishedIncubating);
-
- if (m_cacheMetaType)
- m_cacheMetaType->release();
-}
-
-int QQmlDelegateModelPrivate::adaptorModelCount() const
-{
- // QQmlDelegateModel currently only support list models.
- // So even if a model is a table model, only the first
- // column will be used.
- return m_adaptorModel.rowCount();
-}
-
-void QQmlDelegateModelPrivate::requestMoreIfNecessary()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_waitingToFetchMore && m_adaptorModel.canFetchMore()) {
- m_waitingToFetchMore = true;
- QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
- }
-}
-
-void QQmlDelegateModelPrivate::init()
-{
- Q_Q(QQmlDelegateModel);
- m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
-
- m_items = new QQmlDelegateModelGroup(QStringLiteral("items"), q, Compositor::Default, q);
- m_items->setDefaultInclude(true);
- m_persistedItems = new QQmlDelegateModelGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
- QQmlDelegateModelGroupPrivate::get(m_items)->emitters.insert(this);
-}
-
-QQmlDelegateModel::QQmlDelegateModel()
- : QQmlDelegateModel(nullptr, nullptr)
-{
-}
-
-QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent)
-: QQmlInstanceModel(*(new QQmlDelegateModelPrivate(ctxt)), parent)
-{
- Q_D(QQmlDelegateModel);
- d->init();
-}
-
-QQmlDelegateModel::~QQmlDelegateModel()
-{
- Q_D(QQmlDelegateModel);
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setObject(nullptr, this);
-
- for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) {
- if (cacheItem->object) {
- delete cacheItem->object;
-
- cacheItem->object = nullptr;
- cacheItem->contextData->invalidate();
- Q_ASSERT(cacheItem->contextData->refCount == 1);
- cacheItem->contextData = nullptr;
- cacheItem->scriptRef -= 1;
- }
- cacheItem->groups &= ~Compositor::UnresolvedFlag;
- cacheItem->objectRef = 0;
- if (!cacheItem->isReferenced())
- delete cacheItem;
- else if (cacheItem->incubationTask)
- cacheItem->incubationTask->vdm = nullptr;
- }
-}
-
-
-void QQmlDelegateModel::classBegin()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_context)
- d->m_context = qmlContext(this);
-}
-
-void QQmlDelegateModel::componentComplete()
-{
- Q_D(QQmlDelegateModel);
- d->m_complete = true;
-
- int defaultGroups = 0;
- QStringList groupNames;
- groupNames.append(QStringLiteral("items"));
- groupNames.append(QStringLiteral("persistedItems"));
- if (QQmlDelegateModelGroupPrivate::get(d->m_items)->defaultInclude)
- defaultGroups |= Compositor::DefaultFlag;
- if (QQmlDelegateModelGroupPrivate::get(d->m_persistedItems)->defaultInclude)
- defaultGroups |= Compositor::PersistedFlag;
- for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
- QString name = d->m_groups[i]->name();
- if (name.isEmpty()) {
- d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
- --d->m_groupCount;
- --i;
- } else if (name.at(0).isUpper()) {
- qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter");
- d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
- --d->m_groupCount;
- --i;
- } else {
- groupNames.append(name);
-
- QQmlDelegateModelGroupPrivate *group = QQmlDelegateModelGroupPrivate::get(d->m_groups[i]);
- group->setModel(this, Compositor::Group(i));
- if (group->defaultInclude)
- defaultGroups |= (1 << i);
- }
- }
-
- d->m_cacheMetaType = new QQmlDelegateModelItemMetaType(
- d->m_context->engine()->handle(), this, groupNames);
-
- d->m_compositor.setGroupCount(d->m_groupCount);
- d->m_compositor.setDefaultGroups(defaultGroups);
- d->updateFilterGroup();
-
- while (!d->m_pendingParts.isEmpty())
- static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
-
- QVector<Compositor::Insert> inserts;
- d->m_count = d->adaptorModelCount();
- d->m_compositor.append(
- &d->m_adaptorModel,
- 0,
- d->m_count,
- defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
- &inserts);
- d->itemsInserted(inserts);
- d->emitChanges();
- d->requestMoreIfNecessary();
-}
-
-/*!
- \qmlproperty model QtQml.Models::DelegateModel::model
- This property holds the model providing data for the DelegateModel.
-
- The model provides a set of data that is used to create the items
- for a view. For large or dynamic datasets the model is usually
- provided by a C++ model object. The C++ model object must be a \l
- {QAbstractItemModel} subclass or a simple list.
-
- Models can also be created directly in QML, using a \l{ListModel} or
- \l{QtQuick.XmlListModel::XmlListModel}{XmlListModel}.
-
- \sa {qml-data-models}{Data Models}
- \keyword dm-model-property
-*/
-QVariant QQmlDelegateModel::model() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.model();
-}
-
-void QQmlDelegateModelPrivate::connectToAbstractItemModel()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_adaptorModel.adaptsAim())
- return;
-
- auto aim = m_adaptorModel.aim();
-
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(modelReset()),
- q, QQmlDelegateModel, SLOT(_q_modelReset()));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-}
-
-void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_adaptorModel.adaptsAim())
- return;
-
- auto aim = m_adaptorModel.aim();
-
- QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(aim, SIGNAL(modelReset()),
- q, SLOT(_q_modelReset()));
- QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-}
-
-void QQmlDelegateModel::setModel(const QVariant &model)
-{
- Q_D(QQmlDelegateModel);
-
- if (d->m_complete)
- _q_itemsRemoved(0, d->m_count);
-
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setModel(model, this, d->m_context->engine());
- d->connectToAbstractItemModel();
-
- d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
- for (int i = 0; d->m_parts && i < d->m_parts->models.count(); ++i) {
- d->m_adaptorModel.replaceWatchedRoles(
- QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
- }
-
- if (d->m_complete) {
- _q_itemsInserted(0, d->adaptorModelCount());
- d->requestMoreIfNecessary();
- }
-}
-
-/*!
- \qmlproperty Component QtQml.Models::DelegateModel::delegate
-
- The delegate provides a template defining each item instantiated by a view.
- The index is exposed as an accessible \c index property. Properties of the
- model are also available depending upon the type of \l {qml-data-models}{Data Model}.
-*/
-QQmlComponent *QQmlDelegateModel::delegate() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_delegate;
-}
-
-void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
-{
- Q_D(QQmlDelegateModel);
- if (d->m_transaction) {
- qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated.");
- return;
- }
- if (d->m_delegate == delegate)
- return;
- bool wasValid = d->m_delegate != nullptr;
- d->m_delegate.setObject(delegate, this);
- d->m_delegateValidated = false;
- if (d->m_delegateChooser)
- QObject::disconnect(d->m_delegateChooserChanged);
-
- d->m_delegateChooser = nullptr;
- if (delegate) {
- QQmlAbstractDelegateComponent *adc =
- qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc) {
- d->m_delegateChooser = adc;
- d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
- [d](){ d->delegateChanged(); });
- }
- }
- d->delegateChanged(d->m_delegate, wasValid);
-}
-
-/*!
- \qmlproperty QModelIndex QtQml.Models::DelegateModel::rootIndex
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. \c rootIndex allows the children of
- any node in a QAbstractItemModel to be provided by this model.
-
- This property only affects models of type QAbstractItemModel that
- are hierarchical (e.g, a tree model).
-
- For example, here is a simple interactive file system browser.
- When a directory name is clicked, the view's \c rootIndex is set to the
- QModelIndex node of the clicked directory, thus updating the view to show
- the new directory's contents.
-
- \c main.cpp:
- \snippet delegatemodel/delegatemodel_rootindex/main.cpp 0
-
- \c view.qml:
- \snippet delegatemodel/delegatemodel_rootindex/view.qml 0
-
- If the \l {dm-model-property}{model} is a QAbstractItemModel subclass,
- the delegate can also reference a \c hasModelChildren property (optionally
- qualified by a \e model. prefix) that indicates whether the delegate's
- model item has any child nodes.
-
- \sa modelIndex(), parentModelIndex()
-*/
-QVariant QQmlDelegateModel::rootIndex() const
-{
- Q_D(const QQmlDelegateModel);
- return QVariant::fromValue(QModelIndex(d->m_adaptorModel.rootIndex));
-}
-
-void QQmlDelegateModel::setRootIndex(const QVariant &root)
-{
- Q_D(QQmlDelegateModel);
-
- QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
- const bool changed = d->m_adaptorModel.rootIndex != modelIndex;
- if (changed || !d->m_adaptorModel.isValid()) {
- const int oldCount = d->m_count;
- d->m_adaptorModel.rootIndex = modelIndex;
- if (!d->m_adaptorModel.isValid() && d->m_adaptorModel.aim()) {
- // The previous root index was invalidated, so we need to reconnect the model.
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setModel(d->m_adaptorModel.list.list(), this, d->m_context->engine());
- d->connectToAbstractItemModel();
- }
- if (d->m_adaptorModel.canFetchMore())
- d->m_adaptorModel.fetchMore();
- if (d->m_complete) {
- const int newCount = d->adaptorModelCount();
- if (oldCount)
- _q_itemsRemoved(0, oldCount);
- if (newCount)
- _q_itemsInserted(0, newCount);
- }
- if (changed)
- emit rootIndexChanged();
- }
-}
-
-/*!
- \qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index)
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. This function assists in using
- tree models in QML.
-
- Returns a QModelIndex for the specified index.
- This value can be assigned to rootIndex.
-
- \sa rootIndex
-*/
-QVariant QQmlDelegateModel::modelIndex(int idx) const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.modelIndex(idx);
-}
-
-/*!
- \qmlmethod QModelIndex QtQml.Models::DelegateModel::parentModelIndex()
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. This function assists in using
- tree models in QML.
-
- Returns a QModelIndex for the parent of the current rootIndex.
- This value can be assigned to rootIndex.
-
- \sa rootIndex
-*/
-QVariant QQmlDelegateModel::parentModelIndex() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.parentModelIndex();
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateModel::count
-*/
-
-int QQmlDelegateModel::count() const
-{
- Q_D(const QQmlDelegateModel);
- if (!d->m_delegate)
- return 0;
- return d->m_compositor.count(d->m_compositorGroup);
-}
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object)
-{
- if (!object)
- return QQmlDelegateModel::ReleaseFlags(0);
-
- QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object);
- if (!cacheItem)
- return QQmlDelegateModel::ReleaseFlags(0);
-
- if (!cacheItem->releaseObject())
- return QQmlDelegateModel::Referenced;
-
- cacheItem->destroyObject();
- emitDestroyingItem(object);
- if (cacheItem->incubationTask) {
- releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
- }
- cacheItem->Dispose();
- return QQmlInstanceModel::Destroyed;
-}
-
-/*
- Returns ReleaseStatus flags.
-*/
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item)
-{
- Q_D(QQmlDelegateModel);
- QQmlInstanceModel::ReleaseFlags stat = d->release(item);
- return stat;
-}
-
-// Cancel a requested async item
-void QQmlDelegateModel::cancel(int index)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
- qWarning() << "DelegateModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
- return;
- }
-
- Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
- QQmlDelegateModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
- if (cacheItem) {
- if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
- d->releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
-
- if (cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- d->emitDestroyingPackage(package);
- else
- d->emitDestroyingItem(object);
- }
-
- cacheItem->scriptRef -= 1;
- }
- if (!cacheItem->isReferenced()) {
- d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
- d->m_cache.removeAt(it.cacheIndex);
- delete cacheItem;
- Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
- }
- }
-}
-
-void QQmlDelegateModelPrivate::group_append(
- QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- if (d->m_complete)
- return;
- if (d->m_groupCount == Compositor::MaximumGroupCount) {
- qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8");
- return;
- }
- d->m_groups[d->m_groupCount] = group;
- d->m_groupCount += 1;
-}
-
-int QQmlDelegateModelPrivate::group_count(
- QQmlListProperty<QQmlDelegateModelGroup> *property)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- return d->m_groupCount - 1;
-}
-
-QQmlDelegateModelGroup *QQmlDelegateModelPrivate::group_at(
- QQmlListProperty<QQmlDelegateModelGroup> *property, int index)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- return index >= 0 && index < d->m_groupCount - 1
- ? d->m_groups[index + 1]
- : nullptr;
-}
-
-/*!
- \qmlproperty list<DelegateModelGroup> QtQml.Models::DelegateModel::groups
-
- This property holds a delegate model's group definitions.
-
- Groups define a sub-set of the items in a delegate model and can be used to filter
- a model.
-
- For every group defined in a DelegateModel two attached properties are added to each
- delegate item. The first of the form DelegateModel.in\e{GroupName} holds whether the
- item belongs to the group and the second DelegateModel.\e{groupName}Index holds the
- index of the item in that group.
-
- The following example illustrates using groups to select items in a model.
-
- \snippet delegatemodel/delegatemodelgroup.qml 0
- \keyword dm-groups-property
-*/
-
-QQmlListProperty<QQmlDelegateModelGroup> QQmlDelegateModel::groups()
-{
- Q_D(QQmlDelegateModel);
- return QQmlListProperty<QQmlDelegateModelGroup>(
- this,
- d,
- QQmlDelegateModelPrivate::group_append,
- QQmlDelegateModelPrivate::group_count,
- QQmlDelegateModelPrivate::group_at,
- nullptr);
-}
-
-/*!
- \qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::items
-
- This property holds default group to which all new items are added.
-*/
-
-QQmlDelegateModelGroup *QQmlDelegateModel::items()
-{
- Q_D(QQmlDelegateModel);
- return d->m_items;
-}
-
-/*!
- \qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::persistedItems
-
- This property holds delegate model's persisted items group.
-
- Items in this group are not destroyed when released by a view, instead they are persisted
- until removed from the group.
-
- An item can be removed from the persistedItems group by setting the
- DelegateModel.inPersistedItems property to false. If the item is not referenced by a view
- at that time it will be destroyed. Adding an item to this group will not create a new
- instance.
-
- Items returned by the \l QtQml.Models::DelegateModelGroup::create() function are automatically added
- to this group.
-*/
-
-QQmlDelegateModelGroup *QQmlDelegateModel::persistedItems()
-{
- Q_D(QQmlDelegateModel);
- return d->m_persistedItems;
-}
-
-/*!
- \qmlproperty string QtQml.Models::DelegateModel::filterOnGroup
-
- This property holds name of the group that is used to filter the delegate model.
-
- Only items that belong to this group are visible to a view.
-
- By default this is the \l items group.
-*/
-
-QString QQmlDelegateModel::filterGroup() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_filterGroup;
-}
-
-void QQmlDelegateModel::setFilterGroup(const QString &group)
-{
- Q_D(QQmlDelegateModel);
-
- if (d->m_transaction) {
- qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
- return;
- }
-
- if (d->m_filterGroup != group) {
- d->m_filterGroup = group;
- d->updateFilterGroup();
- emit filterGroupChanged();
- }
-}
-
-void QQmlDelegateModel::resetFilterGroup()
-{
- setFilterGroup(QStringLiteral("items"));
-}
-
-void QQmlDelegateModelPrivate::updateFilterGroup()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_cacheMetaType)
- return;
-
- QQmlListCompositor::Group previousGroup = m_compositorGroup;
- m_compositorGroup = Compositor::Default;
- for (int i = 1; i < m_groupCount; ++i) {
- if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
- m_compositorGroup = Compositor::Group(i);
- break;
- }
- }
-
- QQmlDelegateModelGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
- if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Change> removes;
- QVector<QQmlChangeSet::Change> inserts;
- m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
-
- QQmlChangeSet changeSet;
- changeSet.move(removes, inserts);
- emit q->modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit q->countChanged();
-
- if (m_parts) {
- auto partsCopy = m_parts->models; // deliberate; this may alter m_parts
- for (QQmlPartsModel *model : qAsConst(partsCopy))
- model->updateFilterGroup(m_compositorGroup, changeSet);
- }
- }
-}
-
-/*!
- \qmlproperty object QtQml.Models::DelegateModel::parts
-
- The \a parts property selects a DelegateModel which creates
- delegates from the part named. This is used in conjunction with
- the \l Package type.
-
- For example, the code below selects a model which creates
- delegates named \e list from a \l Package:
-
- \code
- DelegateModel {
- id: visualModel
- delegate: Package {
- Item { Package.name: "list" }
- }
- model: myModel
- }
-
- ListView {
- width: 200; height:200
- model: visualModel.parts.list
- }
- \endcode
-
- \sa Package
-*/
-
-QObject *QQmlDelegateModel::parts()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_parts)
- d->m_parts = new QQmlDelegateModelParts(this);
- return d->m_parts;
-}
-
-const QAbstractItemModel *QQmlDelegateModel::abstractItemModel() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.adaptsAim() ? d->m_adaptorModel.aim() : nullptr;
-}
-
-void QQmlDelegateModelPrivate::emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
-}
-
-void QQmlDelegateModelPrivate::emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
-}
-
-void QQmlDelegateModelPrivate::emitDestroyingPackage(QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->destroyingPackage(package);
-}
-
-static bool isDoneIncubating(QQmlIncubator::Status status)
-{
- return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
-}
-
-void QQDMIncubationTask::statusChanged(Status status)
-{
- if (vdm) {
- vdm->incubatorStatusChanged(this, status);
- } else if (isDoneIncubating(status)) {
- Q_ASSERT(incubating);
- // The model was deleted from under our feet, cleanup ourselves
- delete incubating->object;
- incubating->object = nullptr;
- if (incubating->contextData) {
- incubating->contextData->invalidate();
- Q_ASSERT(incubating->contextData->refCount == 1);
- incubating->contextData = nullptr;
- }
- incubating->scriptRef = 0;
- incubating->deleteLater();
- }
-}
-
-void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTask)
-{
- Q_Q(QQmlDelegateModel);
- if (!incubationTask->isError())
- incubationTask->clear();
- m_finishedIncubating.append(incubationTask);
- if (!m_incubatorCleanupScheduled) {
- m_incubatorCleanupScheduled = true;
- QCoreApplication::postEvent(q, new QEvent(QEvent::User));
- }
-}
-
-void QQmlDelegateModelPrivate::addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it)
-{
- m_cache.insert(it.cacheIndex, item);
- m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
-}
-
-void QQmlDelegateModelPrivate::removeCacheItem(QQmlDelegateModelItem *cacheItem)
-{
- int cidx = m_cache.lastIndexOf(cacheItem);
- if (cidx >= 0) {
- m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
- m_cache.removeAt(cidx);
- }
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
-}
-
-void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status)
-{
- if (!isDoneIncubating(status))
- return;
-
- const QList<QQmlError> incubationTaskErrors = incubationTask->errors();
-
- QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
- cacheItem->incubationTask = nullptr;
- incubationTask->incubating = nullptr;
- releaseIncubator(incubationTask);
-
- if (status == QQmlIncubator::Ready) {
- cacheItem->referenceObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitCreatedPackage(incubationTask, package);
- else
- emitCreatedItem(incubationTask, cacheItem->object);
- cacheItem->releaseObject();
- } else if (status == QQmlIncubator::Error) {
- qmlInfo(m_delegate, incubationTaskErrors + m_delegate->errors()) << "Cannot create delegate";
- }
-
- if (!cacheItem->isObjectReferenced()) {
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(cacheItem->object);
- delete cacheItem->object;
- cacheItem->object = nullptr;
- cacheItem->scriptRef -= 1;
- if (cacheItem->contextData) {
- cacheItem->contextData->invalidate();
- Q_ASSERT(cacheItem->contextData->refCount == 1);
- }
- cacheItem->contextData = nullptr;
-
- if (!cacheItem->isReferenced()) {
- removeCacheItem(cacheItem);
- delete cacheItem;
- }
- }
-}
-
-void QQDMIncubationTask::setInitialState(QObject *o)
-{
- vdm->setInitialState(this, o);
-}
-
-void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
-{
- QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
- cacheItem->object = o;
-
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitInitPackage(incubationTask, package);
- else
- emitInitItem(incubationTask, cacheItem->object);
-}
-
-QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode)
-{
- if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
- qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
- return nullptr;
- } else if (!m_context || !m_context->isValid()) {
- return nullptr;
- }
-
- Compositor::iterator it = m_compositor.find(group, index);
-
- QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
-
- if (!cacheItem) {
- cacheItem = m_adaptorModel.createItem(m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
- return nullptr;
-
- cacheItem->groups = it->flags;
- addCacheItem(cacheItem, it);
- }
-
- // Bump the reference counts temporarily so neither the content data or the delegate object
- // are deleted if incubatorStatusChanged() is called synchronously.
- cacheItem->scriptRef += 1;
- cacheItem->referenceObject();
-
- if (cacheItem->incubationTask) {
- bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
- if (sync && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
- // previously requested async - now needed immediately
- cacheItem->incubationTask->forceCompletion();
- }
- } else if (!cacheItem->object) {
- QQmlComponent *delegate = m_delegate;
- if (m_delegateChooser) {
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, index);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- if (!delegate)
- return nullptr;
- }
-
- QQmlContext *creationContext = delegate->creationContext();
-
- cacheItem->scriptRef += 1;
-
- cacheItem->incubationTask = new QQDMIncubationTask(this, incubationMode);
- cacheItem->incubationTask->incubating = cacheItem;
- cacheItem->incubationTask->clear();
-
- for (int i = 1; i < m_groupCount; ++i)
- cacheItem->incubationTask->index[i] = it.index[i];
-
- QQmlContextData *ctxt = new QQmlContextData;
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
- ctxt->contextObject = cacheItem;
- cacheItem->contextData = ctxt;
-
- if (m_adaptorModel.hasProxyObject()) {
- if (QQmlAdaptorModelProxyInterface *proxy
- = qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem)) {
- ctxt = new QQmlContextData;
- ctxt->setParent(cacheItem->contextData, /*stronglyReferencedByParent*/true);
- QObject *proxied = proxy->proxiedObject();
- ctxt->contextObject = proxied;
- // We don't own the proxied object. We need to clear it if it goes away.
- QObject::connect(proxied, &QObject::destroyed,
- cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);
- }
- }
-
- QQmlComponentPrivate *cp = QQmlComponentPrivate::get(delegate);
- cp->incubateObject(
- cacheItem->incubationTask,
- delegate,
- m_context->engine(),
- ctxt,
- QQmlContextData::get(m_context));
- }
-
- if (index == m_compositor.count(group) - 1)
- requestMoreIfNecessary();
-
- // Remove the temporary reference count.
- cacheItem->scriptRef -= 1;
- if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
- return cacheItem->object;
-
- cacheItem->releaseObject();
- if (!cacheItem->isReferenced()) {
- removeCacheItem(cacheItem);
- delete cacheItem;
- }
-
- return nullptr;
-}
-
-/*
- If asynchronous is true or the component is being loaded asynchronously due
- to an ancestor being loaded asynchronously, object() may return 0. In this
- case createdItem() will be emitted when the object is available. The object
- at this stage does not have any references, so object() must be called again
- to ensure a reference is held. Any call to object() which returns a valid object
- must be matched by a call to release() in order to destroy the object.
-*/
-QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
- qWarning() << "DelegateModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
- return nullptr;
- }
-
- return d->object(d->m_compositorGroup, index, incubationMode);
-}
-
-QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index)
-{
- Q_D(QQmlDelegateModel);
- Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
- if (!it->inCache())
- return QQmlIncubator::Null;
-
- if (auto incubationTask = d->m_cache.at(it.cacheIndex)->incubationTask)
- return incubationTask->status();
-
- return QQmlIncubator::Ready;
-}
-
-QVariant QQmlDelegateModelPrivate::variantValue(QQmlListCompositor::Group group, int index, const QString &name)
-{
- Compositor::iterator it = m_compositor.find(group, index);
- if (QQmlAdaptorModel *model = it.list<QQmlAdaptorModel>()) {
- QString role = name;
- int dot = name.indexOf(QLatin1Char('.'));
- if (dot > 0)
- role = name.left(dot);
- QVariant value = model->value(it.modelIndex(), role);
- while (dot > 0) {
- QObject *obj = qvariant_cast<QObject*>(value);
- if (!obj)
- return QVariant();
- const int from = dot + 1;
- dot = name.indexOf(QLatin1Char('.'), from);
- value = obj->property(name.midRef(from, dot - from).toUtf8());
- }
- return value;
- }
- return QVariant();
-}
-
-QVariant QQmlDelegateModel::variantValue(int index, const QString &role)
-{
- Q_D(QQmlDelegateModel);
- return d->variantValue(d->m_compositorGroup, index, role);
-}
-
-int QQmlDelegateModel::indexOf(QObject *item, QObject *) const
-{
- Q_D(const QQmlDelegateModel);
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(item))
- return cacheItem->groupIndex(d->m_compositorGroup);
- return -1;
-}
-
-void QQmlDelegateModel::setWatchedRoles(const QList<QByteArray> &roles)
-{
- Q_D(QQmlDelegateModel);
- d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
- d->m_watchedRoles = roles;
-}
-
-void QQmlDelegateModelPrivate::addGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Insert> inserts;
- m_compositor.setFlags(from, count, group, groupFlags, &inserts);
- itemsInserted(inserts);
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::removeGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Remove> removes;
- m_compositor.clearFlags(from, count, group, groupFlags, &removes);
- itemsRemoved(removes);
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::setGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
-
- m_compositor.setFlags(from, count, group, groupFlags, &inserts);
- itemsInserted(inserts);
- const int removeFlags = ~groupFlags & Compositor::GroupMask;
-
- from = m_compositor.find(from.group, from.index[from.group]);
- m_compositor.clearFlags(from, count, group, removeFlags, &removes);
- itemsRemoved(removes);
- emitChanges();
-}
-
-bool QQmlDelegateModel::event(QEvent *e)
-{
- Q_D(QQmlDelegateModel);
- if (e->type() == QEvent::UpdateRequest) {
- d->m_waitingToFetchMore = false;
- d->m_adaptorModel.fetchMore();
- } else if (e->type() == QEvent::User) {
- d->m_incubatorCleanupScheduled = false;
- qDeleteAll(d->m_finishedIncubating);
- d->m_finishedIncubating.clear();
- }
- return QQmlInstanceModel::event(e);
-}
-
-void QQmlDelegateModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
-{
- if (!m_delegate)
- return;
-
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
-
- for (const Compositor::Change &change : changes) {
- for (int i = 1; i < m_groupCount; ++i) {
- if (change.inGroup(i)) {
- translatedChanges[i].append(QQmlChangeSet::Change(change.index[i], change.count));
- }
- }
- }
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.change(translatedChanges.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
- QVector<Compositor::Change> changes;
- d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
- d->itemsChanged(changes);
- d->emitChanges();
- }
-}
-
-static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
-{
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < count; ++i)
- incubationTask->index[i] += deltas[i];
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < qMin<int>(count, Compositor::MaximumGroupCount); ++i)
- attached->m_currentIndex[i] += deltas[i];
- }
-}
-
-void QQmlDelegateModelPrivate::itemsInserted(
- const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
-{
- int cacheIndex = 0;
-
- int inserted[Compositor::MaximumGroupCount];
- for (int i = 1; i < m_groupCount; ++i)
- inserted[i] = 0;
-
- for (const Compositor::Insert &insert : inserts) {
- for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
- incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
-
- for (int i = 1; i < m_groupCount; ++i) {
- if (insert.inGroup(i)) {
- (*translatedInserts)[i].append(
- QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId));
- inserted[i] += insert.count;
- }
- }
-
- if (!insert.inCache())
- continue;
-
- if (movedItems && insert.isMove()) {
- QList<QQmlDelegateModelItem *> items = movedItems->take(insert.moveId);
- Q_ASSERT(items.count() == insert.count);
- m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
- }
- if (insert.inGroup()) {
- for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
- QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
- cacheItem->groups |= insert.flags & Compositor::GroupMask;
-
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < m_groupCount; ++i)
- incubationTask->index[i] = cacheItem->groups & (1 << i)
- ? insert.index[i] + offset
- : insert.index[i];
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i)
- attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
- ? insert.index[i] + offset
- : insert.index[i];
- }
- }
- } else {
- cacheIndex = insert.cacheIndex + insert.count;
- }
- }
- for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.count(); ++cacheIndex)
- incrementIndexes(cache.at(cacheIndex), m_groupCount, inserted);
-}
-
-void QQmlDelegateModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
-{
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
- itemsInserted(inserts, &translatedInserts);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- if (!m_delegate)
- return;
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(translatedInserts.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsInserted(int index, int count)
-{
-
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- d->m_count += count;
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- if (item->modelIndex() >= index) {
- const int newIndex = item->modelIndex() + count;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- }
- }
-
- QVector<Compositor::Insert> inserts;
- d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
- d->itemsInserted(inserts);
- d->emitChanges();
-}
-
-//### This method should be split in two. It will remove delegates, and it will re-render the list.
-// When e.g. QQmlListModel::remove is called, the removal of the delegates should be done on
-// QAbstractItemModel::rowsAboutToBeRemoved, and the re-rendering on
-// QAbstractItemModel::rowsRemoved. Currently both are done on the latter signal. The problem is
-// that the destruction of an item will emit a changed signal that ends up at the delegate, which
-// in turn will try to load the data from the model (which should have already freed it), resulting
-// in a use-after-free. See QTBUG-59256.
-void QQmlDelegateModelPrivate::itemsRemoved(
- const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
-{
- int cacheIndex = 0;
- int removedCache = 0;
-
- int removed[Compositor::MaximumGroupCount];
- for (int i = 1; i < m_groupCount; ++i)
- removed[i] = 0;
-
- for (const Compositor::Remove &remove : removes) {
- for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
- incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
-
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i)) {
- (*translatedRemoves)[i].append(
- QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId));
- removed[i] -= remove.count;
- }
- }
-
- if (!remove.inCache())
- continue;
-
- if (movedItems && remove.isMove()) {
- movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
- QList<QQmlDelegateModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
- QList<QQmlDelegateModelItem *>::iterator end = begin + remove.count;
- m_cache.erase(begin, end);
- } else {
- for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
- QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
- if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(object);
- cacheItem->scriptRef -= 1;
- }
- if (!cacheItem->isReferenced()) {
- m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
- m_cache.removeAt(cacheIndex);
- delete cacheItem;
- --cacheIndex;
- ++removedCache;
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- } else if (remove.groups() == cacheItem->groups) {
- cacheItem->groups = 0;
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < m_groupCount; ++i)
- incubationTask->index[i] = -1;
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i)
- attached->m_currentIndex[i] = -1;
- }
- } else {
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- if (!cacheItem->isObjectReferenced()) {
- releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
- if (cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(object);
- }
- cacheItem->scriptRef -= 1;
- } else {
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i))
- incubationTask->index[i] = remove.index[i];
- }
- }
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i))
- attached->m_currentIndex[i] = remove.index[i];
- }
- }
- cacheItem->groups &= ~remove.flags;
- }
- }
- }
- }
-
- for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.count(); ++cacheIndex)
- incrementIndexes(cache.at(cacheIndex), m_groupCount, removed);
-}
-
-void QQmlDelegateModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
-{
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
- itemsRemoved(removes, &translatedRemoves);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- if (!m_delegate)
- return;
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(translatedRemoves.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsRemoved(int index, int count)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0|| !d->m_complete)
- return;
-
- d->m_count -= count;
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- // layout change triggered by removal of a previous item might have
- // already invalidated this item in d->m_cache and deleted it
- if (!d->m_cache.contains(item))
- continue;
-
- if (item->modelIndex() >= index + count) {
- const int newIndex = item->modelIndex() - count;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- } else if (item->modelIndex() >= index) {
- item->setModelIndex(-1, -1, -1);
- }
- }
-
- QVector<Compositor::Remove> removes;
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
- d->itemsRemoved(removes);
-
- d->emitChanges();
-}
-
-void QQmlDelegateModelPrivate::itemsMoved(
- const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
-{
- QHash<int, QList<QQmlDelegateModelItem *> > movedItems;
-
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
- itemsRemoved(removes, &translatedRemoves, &movedItems);
-
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
- itemsInserted(inserts, &translatedInserts, &movedItems);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- Q_ASSERT(movedItems.isEmpty());
- if (!m_delegate)
- return;
-
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.move(
- translatedRemoves.at(i),
- translatedInserts.at(i));
- }
-}
-
-void QQmlDelegateModel::_q_itemsMoved(int from, int to, int count)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- const int minimum = qMin(from, to);
- const int maximum = qMax(from, to) + count;
- const int difference = from > to ? count : -count;
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- if (item->modelIndex() >= from && item->modelIndex() < from + count) {
- const int newIndex = item->modelIndex() - from + to;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- } else if (item->modelIndex() >= minimum && item->modelIndex() < maximum) {
- const int newIndex = item->modelIndex() + difference;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- }
- }
-
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
- d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
- d->itemsMoved(removes, inserts);
- d->emitChanges();
-}
-
-void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- Q_Q(QQmlDelegateModel);
- emit q->modelUpdated(changeSet, reset);
- if (changeSet.difference() != 0)
- emit q->countChanged();
-}
-
-void QQmlDelegateModelPrivate::delegateChanged(bool add, bool remove)
-{
- Q_Q(QQmlDelegateModel);
- if (!m_complete)
- return;
-
- if (m_transaction) {
- qmlWarning(q) << QQmlDelegateModel::tr("The delegates of a DelegateModel cannot be changed within onUpdated.");
- return;
- }
-
- if (remove) {
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(
- 0, m_compositor.count(Compositor::Group(i)));
- }
- }
- if (add) {
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(
- 0, m_compositor.count(Compositor::Group(i)));
- }
- }
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::emitChanges()
-{
- if (m_transaction || !m_complete || !m_context || !m_context->isValid())
- return;
-
- m_transaction = true;
- QV4::ExecutionEngine *engine = m_context->engine()->handle();
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitChanges(engine);
- m_transaction = false;
-
- const bool reset = m_reset;
- m_reset = false;
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
-
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
- if (cacheItem->attached)
- cacheItem->attached->emitChanges();
- }
-}
-
-void QQmlDelegateModel::_q_modelReset()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate)
- return;
-
- int oldCount = d->m_count;
- d->m_adaptorModel.rootIndex = QModelIndex();
-
- if (d->m_complete) {
- d->m_count = d->adaptorModelCount();
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- if (item->modelIndex() != -1)
- item->setModelIndex(-1, -1, -1);
- }
-
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
- if (oldCount)
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
- if (d->m_count)
- d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
- d->itemsMoved(removes, inserts);
- d->m_reset = true;
-
- if (d->m_adaptorModel.canFetchMore())
- d->m_adaptorModel.fetchMore();
-
- d->emitChanges();
- }
- emit rootIndexChanged();
-}
-
-void QQmlDelegateModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (parent == d->m_adaptorModel.rootIndex)
- _q_itemsInserted(begin, end - begin + 1);
-}
-
-void QQmlDelegateModel::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_adaptorModel.rootIndex.isValid())
- return;
- const QModelIndex index = d->m_adaptorModel.rootIndex;
- if (index.parent() == parent && index.row() >= begin && index.row() <= end) {
- const int oldCount = d->m_count;
- d->m_count = 0;
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.invalidateModel();
-
- if (d->m_complete && oldCount > 0) {
- QVector<Compositor::Remove> removes;
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
- d->itemsRemoved(removes);
- d->emitChanges();
- }
- }
-}
-
-void QQmlDelegateModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (parent == d->m_adaptorModel.rootIndex)
- _q_itemsRemoved(begin, end - begin + 1);
-}
-
-void QQmlDelegateModel::_q_rowsMoved(
- const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
- const QModelIndex &destinationParent, int destinationRow)
-{
- Q_D(QQmlDelegateModel);
- const int count = sourceEnd - sourceStart + 1;
- if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
- _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
- } else if (sourceParent == d->m_adaptorModel.rootIndex) {
- _q_itemsRemoved(sourceStart, count);
- } else if (destinationParent == d->m_adaptorModel.rootIndex) {
- _q_itemsInserted(destinationRow, count);
- }
-}
-
-void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
-{
- Q_D(QQmlDelegateModel);
- if (begin.parent() == d->m_adaptorModel.rootIndex)
- _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
-}
-
-bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
-{
- for (int i = 0, c = parents.count(); i < c; ++i) {
- for (QPersistentModelIndex parent = desc; parent.isValid(); parent = parent.parent()) {
- if (parent == parents[i])
- return true;
- }
- }
-
- return false;
-}
-
-void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_complete)
- return;
-
- if (hint == QAbstractItemModel::VerticalSortHint) {
- if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
- return;
- }
-
- // mark all items as changed
- _q_itemsChanged(0, d->m_count, QVector<int>());
-
- } else if (hint == QAbstractItemModel::HorizontalSortHint) {
- // Ignored
- } else {
- // We don't know what's going on, so reset the model
- _q_modelReset();
- }
-}
-
-QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj)
-{
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(obj)) {
- if (cacheItem->object == obj) { // Don't create attached item for child objects.
- cacheItem->attached = new QQmlDelegateModelAttached(cacheItem, obj);
- return cacheItem->attached;
- }
- }
- return new QQmlDelegateModelAttached(obj);
-}
-
-bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
-{
- if (!m_context || !m_context->isValid())
- return false;
-
- QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, -1);
- if (!cacheItem)
- return false;
- if (!object.isObject())
- return false;
-
- QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, object);
- if (!o)
- return false;
-
- QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedValue propertyName(scope);
- QV4::ScopedValue v(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(v);
- if (propertyName->isNull())
- break;
- cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QVariant::Invalid));
- }
-
- cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
-
- // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
- itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
-
- before = m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
- m_cache.insert(before.cacheIndex, cacheItem);
-
- return true;
-}
-
-//============================================================================
-
-QQmlDelegateModelItemMetaType::QQmlDelegateModelItemMetaType(
- QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames)
- : model(model)
- , groupCount(groupNames.count() + 1)
- , v4Engine(engine)
- , metaObject(nullptr)
- , groupNames(groupNames)
-{
-}
-
-QQmlDelegateModelItemMetaType::~QQmlDelegateModelItemMetaType()
-{
- if (metaObject)
- metaObject->release();
-}
-
-void QQmlDelegateModelItemMetaType::initializeMetaObject()
-{
- QMetaObjectBuilder builder;
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- builder.setClassName(QQmlDelegateModelAttached::staticMetaObject.className());
- builder.setSuperClass(&QQmlDelegateModelAttached::staticMetaObject);
-
- int notifierId = 0;
- for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- QString propertyName = QLatin1String("in") + groupNames.at(i);
- propertyName.replace(2, 1, propertyName.at(2).toUpper());
- builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
- QMetaPropertyBuilder propertyBuilder = builder.addProperty(
- propertyName.toUtf8(), "bool", notifierId);
- propertyBuilder.setWritable(true);
- }
- for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- const QString propertyName = groupNames.at(i) + QLatin1String("Index");
- builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
- QMetaPropertyBuilder propertyBuilder = builder.addProperty(
- propertyName.toUtf8(), "int", notifierId);
- propertyBuilder.setWritable(true);
- }
-
- metaObject = new QQmlDelegateModelAttachedMetaObject(this, builder.toMetaObject());
-}
-
-void QQmlDelegateModelItemMetaType::initializePrototype()
-{
- QV4::Scope scope(v4Engine);
-
- QV4::ScopedObject proto(scope, v4Engine->newObject());
- proto->defineAccessorProperty(QStringLiteral("model"), QQmlDelegateModelItem::get_model, nullptr);
- proto->defineAccessorProperty(QStringLiteral("groups"), QQmlDelegateModelItem::get_groups, QQmlDelegateModelItem::set_groups);
- QV4::ScopedString s(scope);
- QV4::ScopedProperty p(scope);
-
- s = v4Engine->newString(QStringLiteral("isUnresolved"));
- QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- for (int i = 2; i < groupNames.count(); ++i) {
- QString propertyName = QLatin1String("in") + groupNames.at(i);
- propertyName.replace(2, 1, propertyName.at(2).toUpper());
- s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- }
- for (int i = 2; i < groupNames.count(); ++i) {
- const QString propertyName = groupNames.at(i) + QLatin1String("Index");
- s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- }
- modelItemProto.set(v4Engine, proto);
-}
-
-int QQmlDelegateModelItemMetaType::parseGroups(const QStringList &groups) const
-{
- int groupFlags = 0;
- for (const QString &groupName : groups) {
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- }
- return groupFlags;
-}
-
-int QQmlDelegateModelItemMetaType::parseGroups(const QV4::Value &groups) const
-{
- int groupFlags = 0;
- QV4::Scope scope(v4Engine);
-
- QV4::ScopedString s(scope, groups);
- if (s) {
- const QString groupName = s->toQString();
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- return groupFlags;
- }
-
- QV4::ScopedArrayObject array(scope, groups);
- if (array) {
- QV4::ScopedValue v(scope);
- uint arrayLength = array->getLength();
- for (uint i = 0; i < arrayLength; ++i) {
- v = array->get(i);
- const QString groupName = v->toQString();
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- }
- }
- return groupFlags;
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_model(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return b->engine()->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!o->d()->item->metaType->model)
- RETURN_UNDEFINED();
-
- return o->d()->item->get();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_groups(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- QStringList groups;
- for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
- if (o->d()->item->groups & (1 << i))
- groups.append(o->d()->item->metaType->groupNames.at(i - 1));
- }
-
- return scope.engine->fromVariant(groups);
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::set_groups(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- if (!argc)
- THROW_TYPE_ERROR();
-
- if (!o->d()->item->metaType->model)
- RETURN_UNDEFINED();
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
-
- const int groupFlags = model->m_cacheMetaType->parseGroups(argv[0]);
- const int cacheIndex = model->m_cache.indexOf(o->d()->item);
- Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
- model->setGroups(it, 1, Compositor::Cache, groupFlags);
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
-{
- return QV4::Encode(bool(thisItem->groups & (1 << flag)));
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::set_member(QQmlDelegateModelItem *cacheItem, uint flag, const QV4::Value &arg)
-{
- if (!cacheItem->metaType->model)
- return QV4::Encode::undefined();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(cacheItem->metaType->model);
-
- bool member = arg.toBoolean();
- uint groupFlag = (1 << flag);
- if (member == ((cacheItem->groups & groupFlag) != 0))
- return QV4::Encode::undefined();
-
- const int cacheIndex = model->m_cache.indexOf(cacheItem);
- Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
- if (member)
- model->addGroups(it, 1, Compositor::Cache, groupFlag);
- else
- model->removeGroups(it, 1, Compositor::Cache, groupFlag);
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
-{
- return QV4::Encode((int)thisItem->groupIndex(Compositor::Group(flag)));
-}
-
-void QQmlDelegateModelItem::childContextObjectDestroyed(QObject *childContextObject)
-{
- if (!contextData)
- return;
-
- for (QQmlContextData *ctxt = contextData->childContexts; ctxt; ctxt = ctxt->nextChild) {
- if (ctxt->contextObject == childContextObject)
- ctxt->contextObject = nullptr;
- }
-}
-
-
-//---------------------------------------------------------------------------
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelItemObject);
-
-void QV4::Heap::QQmlDelegateModelItemObject::destroy()
-{
- item->Dispose();
- Object::destroy();
-}
-
-
-QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int modelIndex, int row, int column)
- : v4(metaType->v4Engine)
- , metaType(metaType)
- , contextData(nullptr)
- , object(nullptr)
- , attached(nullptr)
- , incubationTask(nullptr)
- , delegate(nullptr)
- , poolTime(0)
- , objectRef(0)
- , scriptRef(0)
- , groups(0)
- , index(modelIndex)
- , row(row)
- , column(column)
-{
- metaType->addref();
-
- if (accessor->propertyCache) {
- // The property cache in the accessor is common for all the model
- // items in the model it wraps. It describes available model roles,
- // together with revisioned properties like row, column and index, all
- // which should be available in the delegate. We assign this cache to the
- // model item so that the QML engine can use the revision information
- // when resolving the properties (rather than falling back to just
- // inspecting the QObject in the model item directly).
- QQmlData *qmldata = QQmlData::get(this, true);
- if (qmldata->propertyCache)
- qmldata->propertyCache->release();
- qmldata->propertyCache = accessor->propertyCache.data();
- qmldata->propertyCache->addref();
- }
-}
-
-QQmlDelegateModelItem::~QQmlDelegateModelItem()
-{
- Q_ASSERT(scriptRef == 0);
- Q_ASSERT(objectRef == 0);
- Q_ASSERT(!object);
-
- if (incubationTask) {
- if (metaType->model)
- QQmlDelegateModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
- else
- delete incubationTask;
- }
-
- metaType->release();
-
-}
-
-void QQmlDelegateModelItem::Dispose()
-{
- --scriptRef;
- if (isReferenced())
- return;
-
- if (metaType->model) {
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
- model->removeCacheItem(this);
- }
- delete this;
-}
-
-void QQmlDelegateModelItem::setModelIndex(int idx, int newRow, int newColumn)
-{
- const int prevIndex = index;
- const int prevRow = row;
- const int prevColumn = column;
-
- index = idx;
- row = newRow;
- column = newColumn;
-
- if (idx != prevIndex)
- emit modelIndexChanged();
- if (row != prevRow)
- emit rowChanged();
- if (column != prevColumn)
- emit columnChanged();
-}
-
-void QQmlDelegateModelItem::destroyObject()
-{
- Q_ASSERT(object);
- Q_ASSERT(contextData);
-
- QQmlData *data = QQmlData::get(object);
- Q_ASSERT(data);
- if (data->ownContext) {
- data->ownContext->clearContext();
- if (data->ownContext->contextObject == object)
- data->ownContext->contextObject = nullptr;
- data->ownContext = nullptr;
- data->context = nullptr;
- }
- object->deleteLater();
-
- if (attached) {
- attached->m_cacheItem = nullptr;
- attached = nullptr;
- }
-
- contextData->invalidate();
- contextData = nullptr;
- object = nullptr;
-}
-
-QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
-{
- QQmlData *d = QQmlData::get(object);
- QQmlContextData *context = d ? d->context : nullptr;
- for (context = context ? context->parent : nullptr; context; context = context->parent) {
- if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
- context->contextObject)) {
- return cacheItem;
- }
- }
- return nullptr;
-}
-
-int QQmlDelegateModelItem::groupIndex(Compositor::Group group)
-{
- if (QQmlDelegateModelPrivate * const model = metaType->model
- ? QQmlDelegateModelPrivate::get(metaType->model)
- : nullptr) {
- return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
- }
- return -1;
-}
-
-//---------------------------------------------------------------------------
-
-QQmlDelegateModelAttachedMetaObject::QQmlDelegateModelAttachedMetaObject(
- QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject)
- : metaType(metaType)
- , metaObject(metaObject)
- , memberPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount())
- , indexPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
-{
- // Don't reference count the meta-type here as that would create a circular reference.
- // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
- // destroying all delegates with attached objects.
- *static_cast<QMetaObject *>(this) = *metaObject;
-}
-
-QQmlDelegateModelAttachedMetaObject::~QQmlDelegateModelAttachedMetaObject()
-{
- ::free(metaObject);
-}
-
-void QQmlDelegateModelAttachedMetaObject::objectDestroyed(QObject *)
-{
- release();
-}
-
-int QQmlDelegateModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
-{
- QQmlDelegateModelAttached *attached = static_cast<QQmlDelegateModelAttached *>(object);
- if (call == QMetaObject::ReadProperty) {
- if (_id >= indexPropertyOffset) {
- Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
- *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
- return -1;
- } else if (_id >= memberPropertyOffset) {
- Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
- *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
- return -1;
- }
- } else if (call == QMetaObject::WriteProperty) {
- if (_id >= memberPropertyOffset) {
- if (!metaType->model)
- return -1;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
- Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
- const int groupFlag = 1 << group;
- const bool member = attached->m_cacheItem->groups & groupFlag;
- if (member && !*static_cast<bool *>(arguments[0])) {
- Compositor::iterator it = model->m_compositor.find(
- group, attached->m_currentIndex[group]);
- model->removeGroups(it, 1, group, groupFlag);
- } else if (!member && *static_cast<bool *>(arguments[0])) {
- for (int i = 1; i < metaType->groupCount; ++i) {
- if (attached->m_cacheItem->groups & (1 << i)) {
- Compositor::iterator it = model->m_compositor.find(
- Compositor::Group(i), attached->m_currentIndex[i]);
- model->addGroups(it, 1, Compositor::Group(i), groupFlag);
- break;
- }
- }
- }
- return -1;
- }
- }
- return attached->qt_metacall(call, _id, arguments);
-}
-
-QQmlDelegateModelAttached::QQmlDelegateModelAttached(QObject *parent)
- : m_cacheItem(nullptr)
- , m_previousGroups(0)
-{
- QQml_setParent_noEvent(this, parent);
-}
-
-QQmlDelegateModelAttached::QQmlDelegateModelAttached(
- QQmlDelegateModelItem *cacheItem, QObject *parent)
- : m_cacheItem(cacheItem)
- , m_previousGroups(cacheItem->groups)
-{
- QQml_setParent_noEvent(this, parent);
- resetCurrentIndex();
- // Let m_previousIndex be equal to m_currentIndex
- std::copy(std::begin(m_currentIndex), std::end(m_currentIndex), std::begin(m_previousIndex));
-
- if (!cacheItem->metaType->metaObject)
- cacheItem->metaType->initializeMetaObject();
-
- QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
- cacheItem->metaType->metaObject->addref();
-}
-
-void QQmlDelegateModelAttached::resetCurrentIndex()
-{
- if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
- for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i)
- m_currentIndex[i] = incubationTask->index[i];
- } else {
- QQmlDelegateModelPrivate * const model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
- Compositor::iterator it = model->m_compositor.find(
- Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
- m_currentIndex[i] = it.index[i];
- }
-}
-
-/*!
- \qmlattachedproperty model QtQml.Models::DelegateModel::model
-
- This attached property holds the data model this delegate instance belongs to.
-
- It is attached to each instance of the delegate.
-*/
-
-QQmlDelegateModel *QQmlDelegateModelAttached::model() const
-{
- return m_cacheItem ? m_cacheItem->metaType->model : nullptr;
-}
-
-/*!
- \qmlattachedproperty stringlist QtQml.Models::DelegateModel::groups
-
- This attached property holds the name of DelegateModelGroups the item belongs to.
-
- It is attached to each instance of the delegate.
-*/
-
-QStringList QQmlDelegateModelAttached::groups() const
-{
- QStringList groups;
-
- if (!m_cacheItem)
- return groups;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
- if (m_cacheItem->groups & (1 << i))
- groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
- }
- return groups;
-}
-
-void QQmlDelegateModelAttached::setGroups(const QStringList &groups)
-{
- if (!m_cacheItem)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
-
- const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
- const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
- Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
- model->setGroups(it, 1, Compositor::Cache, groupFlags);
-}
-
-/*!
- \qmlattachedproperty bool QtQml.Models::DelegateModel::isUnresolved
-
- This attached property indicates whether the visual item is bound to a data model index.
- Returns true if the item is not bound to the model, and false if it is.
-
- An unresolved item can be bound to the data model using the DelegateModelGroup::resolve()
- function.
-
- It is attached to each instance of the delegate.
-*/
-
-bool QQmlDelegateModelAttached::isUnresolved() const
-{
- if (!m_cacheItem)
- return false;
-
- return m_cacheItem->groups & Compositor::UnresolvedFlag;
-}
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::inItems
-
- This attached property holds whether the item belongs to the default \l items DelegateModelGroup.
-
- Changing this property will add or remove the item from the items group.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::itemsIndex
-
- This attached property holds the index of the item in the default \l items DelegateModelGroup.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::inPersistedItems
-
- This attached property holds whether the item belongs to the \l persistedItems DelegateModelGroup.
-
- Changing this property will add or remove the item from the items group. Change with caution
- as removing an item from the persistedItems group will destroy the current instance if it is
- not referenced by a model.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::persistedItemsIndex
-
- This attached property holds the index of the item in the \l persistedItems DelegateModelGroup.
-
- It is attached to each instance of the delegate.
-*/
-
-void QQmlDelegateModelAttached::emitChanges()
-{
- const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
- m_previousGroups = m_cacheItem->groups;
-
- int indexChanges = 0;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
- if (m_previousIndex[i] != m_currentIndex[i]) {
- m_previousIndex[i] = m_currentIndex[i];
- indexChanges |= (1 << i);
- }
- }
-
- int notifierId = 0;
- const QMetaObject *meta = metaObject();
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
- if (groupChanges & (1 << i))
- QMetaObject::activate(this, meta, notifierId, nullptr);
- }
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
- if (indexChanges & (1 << i))
- QMetaObject::activate(this, meta, notifierId, nullptr);
- }
-
- if (groupChanges)
- emit groupsChanged();
-}
-
-//============================================================================
-
-void QQmlDelegateModelGroupPrivate::setModel(QQmlDelegateModel *m, Compositor::Group g)
-{
- Q_ASSERT(!model);
- model = m;
- group = g;
-}
-
-bool QQmlDelegateModelGroupPrivate::isChangedConnected()
-{
- Q_Q(QQmlDelegateModelGroup);
- IS_SIGNAL_CONNECTED(q, QQmlDelegateModelGroup, changed, (const QJSValue &,const QJSValue &));
-}
-
-void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
-{
- Q_Q(QQmlDelegateModelGroup);
- if (isChangedConnected() && !changeSet.isEmpty()) {
- emit q->changed(QJSValue(v4, engineData(v4)->array(v4, changeSet.removes())),
- QJSValue(v4, engineData(v4)->array(v4, changeSet.inserts())));
- }
- if (changeSet.difference() != 0)
- emit q->countChanged();
-}
-
-void QQmlDelegateModelGroupPrivate::emitModelUpdated(bool reset)
-{
- for (QQmlDelegateModelGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
- it->emitModelUpdated(changeSet, reset);
- changeSet.clear();
-}
-
-typedef QQmlDelegateModelGroupEmitterList::iterator GroupEmitterListIt;
-
-void QQmlDelegateModelGroupPrivate::createdPackage(int index, QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->createdPackage(index, package);
-}
-
-void QQmlDelegateModelGroupPrivate::initPackage(int index, QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->initPackage(index, package);
-}
-
-void QQmlDelegateModelGroupPrivate::destroyingPackage(QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->destroyingPackage(package);
-}
-
-/*!
- \qmltype DelegateModelGroup
- \instantiates QQmlDelegateModelGroup
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Encapsulates a filtered set of visual data items.
-
- The DelegateModelGroup type provides a means to address the model data of a
- DelegateModel's delegate items, as well as sort and filter these delegate
- items.
-
- The initial set of instantiable delegate items in a DelegateModel is represented
- by its \l {QtQml.Models::DelegateModel::items}{items} group, which normally directly reflects
- the contents of the model assigned to DelegateModel::model. This set can be changed to
- the contents of any other member of DelegateModel::groups by assigning the \l name of that
- DelegateModelGroup to the DelegateModel::filterOnGroup property.
-
- The data of an item in a DelegateModelGroup can be accessed using the get() function, which returns
- information about group membership and indexes as well as model data. In combination
- with the move() function this can be used to implement view sorting, with remove() to filter
- items out of a view, or with setGroups() and \l Package delegates to categorize items into
- different views. Different groups can only be sorted independently if they are disjunct. Moving
- an item in one group will also move it in all other groups it is a part of.
-
- Data from models can be supplemented by inserting data directly into a DelegateModelGroup
- with the insert() function. This can be used to introduce mock items into a view, or
- placeholder items that are later \l {resolve()}{resolved} to real model data when it becomes
- available.
-
- Delegate items can also be instantiated directly from a DelegateModelGroup using the
- create() function, making it possible to use DelegateModel without an accompanying view
- type or to cherry-pick specific items that should be instantiated irregardless of whether
- they're currently within a view's visible area.
-
- \sa {QML Dynamic View Ordering Tutorial}
-*/
-QQmlDelegateModelGroup::QQmlDelegateModelGroup(QObject *parent)
- : QObject(*new QQmlDelegateModelGroupPrivate, parent)
-{
-}
-
-QQmlDelegateModelGroup::QQmlDelegateModelGroup(
- const QString &name, QQmlDelegateModel *model, int index, QObject *parent)
- : QQmlDelegateModelGroup(parent)
-{
- Q_D(QQmlDelegateModelGroup);
- d->name = name;
- d->setModel(model, Compositor::Group(index));
-}
-
-QQmlDelegateModelGroup::~QQmlDelegateModelGroup()
-{
-}
-
-/*!
- \qmlproperty string QtQml.Models::DelegateModelGroup::name
-
- This property holds the name of the group.
-
- Each group in a model must have a unique name starting with a lower case letter.
-*/
-
-QString QQmlDelegateModelGroup::name() const
-{
- Q_D(const QQmlDelegateModelGroup);
- return d->name;
-}
-
-void QQmlDelegateModelGroup::setName(const QString &name)
-{
- Q_D(QQmlDelegateModelGroup);
- if (d->model)
- return;
- if (d->name != name) {
- d->name = name;
- emit nameChanged();
- }
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateModelGroup::count
-
- This property holds the number of items in the group.
-*/
-
-int QQmlDelegateModelGroup::count() const
-{
- Q_D(const QQmlDelegateModelGroup);
- if (!d->model)
- return 0;
- return QQmlDelegateModelPrivate::get(d->model)->m_compositor.count(d->group);
-}
-
-/*!
- \qmlproperty bool QtQml.Models::DelegateModelGroup::includeByDefault
-
- This property holds whether new items are assigned to this group by default.
-*/
-
-bool QQmlDelegateModelGroup::defaultInclude() const
-{
- Q_D(const QQmlDelegateModelGroup);
- return d->defaultInclude;
-}
-
-void QQmlDelegateModelGroup::setDefaultInclude(bool include)
-{
- Q_D(QQmlDelegateModelGroup);
- if (d->defaultInclude != include) {
- d->defaultInclude = include;
-
- if (d->model) {
- if (include)
- QQmlDelegateModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
- else
- QQmlDelegateModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
- }
- emit defaultIncludeChanged();
- }
-}
-
-/*!
- \qmlmethod object QtQml.Models::DelegateModelGroup::get(int index)
-
- Returns a javascript object describing the item at \a index in the group.
-
- The returned object contains the same information that is available to a delegate from the
- DelegateModel attached as well as the model for that item. It has the properties:
-
- \list
- \li \b model The model data of the item. This is the same as the model context property in
- a delegate
- \li \b groups A list the of names of groups the item is a member of. This property can be
- written to change the item's membership.
- \li \b inItems Whether the item belongs to the \l {QtQml.Models::DelegateModel::items}{items} group.
- Writing to this property will add or remove the item from the group.
- \li \b itemsIndex The index of the item within the \l {QtQml.Models::DelegateModel::items}{items} group.
- \li \b {in<GroupName>} Whether the item belongs to the dynamic group \e groupName. Writing to
- this property will add or remove the item from the group.
- \li \b {<groupName>Index} The index of the item within the dynamic group \e groupName.
- \li \b isUnresolved Whether the item is bound to an index in the model assigned to
- DelegateModel::model. Returns true if the item is not bound to the model, and false if it is.
- \endlist
-*/
-
-QJSValue QQmlDelegateModelGroup::get(int index)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return QJSValue();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (!model->m_context || !model->m_context->isValid()) {
- return QJSValue();
- } else if (index < 0 || index >= model->m_compositor.count(d->group)) {
- qmlWarning(this) << tr("get: index out of range");
- return QJSValue();
- }
-
- Compositor::iterator it = model->m_compositor.find(d->group, index);
- QQmlDelegateModelItem *cacheItem = it->inCache()
- ? model->m_cache.at(it.cacheIndex)
- : 0;
-
- if (!cacheItem) {
- cacheItem = model->m_adaptorModel.createItem(
- model->m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
- return QJSValue();
- cacheItem->groups = it->flags;
-
- model->m_cache.insert(it.cacheIndex, cacheItem);
- model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- }
-
- if (model->m_cacheMetaType->modelItemProto.isUndefined())
- model->m_cacheMetaType->initializePrototype();
- QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine;
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(cacheItem));
- QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
- o->setPrototypeOf(p);
- ++cacheItem->scriptRef;
-
- return QJSValue(v4, o->asReturnedValue());
-}
-
-bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
-{
- if (value.isNumber()) {
- *index = value.toInt32();
- return true;
- }
-
- if (!value.isObject())
- return false;
-
- QV4::ExecutionEngine *v4 = value.as<QV4::Object>()->engine();
- QV4::Scope scope(v4);
- QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value);
-
- if (object) {
- QQmlDelegateModelItem * const cacheItem = object->d()->item;
- if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
- ? QQmlDelegateModelPrivate::get(cacheItem->metaType->model)
- : nullptr) {
- *index = model->m_cache.indexOf(cacheItem);
- *group = Compositor::Cache;
- return true;
- }
- }
- return false;
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::insert(int index, jsdict data, array groups = undefined)
- \qmlmethod QtQml.Models::DelegateModelGroup::insert(jsdict data, var groups = undefined)
-
- Creates a new entry at \a index in a DelegateModel with the values from \a data that
- correspond to roles in the model assigned to DelegateModel::model.
-
- If no index is supplied the data is appended to the model.
-
- The optional \a groups parameter identifies the groups the new entry should belong to,
- if unspecified this is equal to the group insert was called on.
-
- Data inserted into a DelegateModel can later be merged with an existing entry in
- DelegateModel::model using the \l resolve() function. This can be used to create placeholder
- items that are later replaced by actual data.
-*/
-
-void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- int index = model->m_compositor.count(d->group);
- Compositor::Group group = d->group;
-
- if (args->length() == 0)
- return;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (d->parseIndex(v, &index, &group)) {
- if (index < 0 || index > model->m_compositor.count(group)) {
- qmlWarning(this) << tr("insert: index out of range");
- return;
- }
- if (++i == args->length())
- return;
- v = (*args)[i];
- }
-
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
-
- int groups = 1 << d->group;
- if (++i < args->length()) {
- QV4::ScopedValue val(scope, (*args)[i]);
- groups |= model->m_cacheMetaType->parseGroups(val);
- }
-
- if (v->as<QV4::ArrayObject>()) {
- return;
- } else if (v->as<QV4::Object>()) {
- model->insert(before, v, groups);
- model->emitChanges();
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::create(int index)
- \qmlmethod QtQml.Models::DelegateModelGroup::create(int index, jsdict data, array groups = undefined)
- \qmlmethod QtQml.Models::DelegateModelGroup::create(jsdict data, array groups = undefined)
-
- Returns a reference to the instantiated item at \a index in the group.
-
- If a \a data object is provided it will be \l {insert}{inserted} at \a index and an item
- referencing this new entry will be returned. The optional \a groups parameter identifies
- the groups the new entry should belong to, if unspecified this is equal to the group create()
- was called on.
-
- All items returned by create are added to the
- \l {QtQml.Models::DelegateModel::persistedItems}{persistedItems} group. Items in this
- group remain instantiated when not referenced by any view.
-*/
-
-void QQmlDelegateModelGroup::create(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
-
- if (args->length() == 0)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- int index = model->m_compositor.count(d->group);
- Compositor::Group group = d->group;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (d->parseIndex(v, &index, &group))
- ++i;
-
- if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) {
- v = (*args)[i];
- if (v->as<QV4::Object>()) {
- int groups = 1 << d->group;
- if (++i < args->length()) {
- QV4::ScopedValue val(scope, (*args)[i]);
- groups |= model->m_cacheMetaType->parseGroups(val);
- }
-
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
-
- index = before.index[d->group];
- group = d->group;
-
- if (!model->insert(before, v, groups)) {
- return;
- }
- }
- }
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("create: index out of range");
- return;
- }
-
- QObject *object = model->object(group, index, QQmlIncubator::AsynchronousIfNested);
- if (object) {
- QVector<Compositor::Insert> inserts;
- Compositor::iterator it = model->m_compositor.find(group, index);
- model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
- model->itemsInserted(inserts);
- model->m_cache.at(it.cacheIndex)->releaseObject();
- }
-
- args->setReturnValue(QV4::QObjectWrapper::wrap(args->v4engine(), object));
- model->emitChanges();
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::resolve(int from, int to)
-
- Binds an unresolved item at \a from to an item in DelegateModel::model at index \a to.
-
- Unresolved items are entries whose data has been \l {insert()}{inserted} into a DelegateModelGroup
- instead of being derived from a DelegateModel::model index. Resolving an item will replace
- the item at the target index with the unresolved item. A resolved an item will reflect the data
- of the source model at its bound index and will move when that index moves like any other item.
-
- If a new item is replaced in the DelegateModelGroup onChanged() handler its insertion and
- replacement will be communicated to views as an atomic operation, creating the appearance
- that the model contents have not changed, or if the unresolved and model item are not adjacent
- that the previously unresolved item has simply moved.
-
-*/
-void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- if (args->length() < 2)
- return;
-
- int from = -1;
- int to = -1;
- Compositor::Group fromGroup = d->group;
- Compositor::Group toGroup = d->group;
-
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (d->parseIndex(v, &from, &fromGroup)) {
- if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
- qmlWarning(this) << tr("resolve: from index out of range");
- return;
- }
- } else {
- qmlWarning(this) << tr("resolve: from index invalid");
- return;
- }
-
- v = (*args)[1];
- if (d->parseIndex(v, &to, &toGroup)) {
- if (to < 0 || to >= model->m_compositor.count(toGroup)) {
- qmlWarning(this) << tr("resolve: to index out of range");
- return;
- }
- } else {
- qmlWarning(this) << tr("resolve: to index invalid");
- return;
- }
-
- Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
- Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
-
- if (!fromIt->isUnresolved()) {
- qmlWarning(this) << tr("resolve: from is not an unresolved item");
- return;
- }
- if (!toIt->list) {
- qmlWarning(this) << tr("resolve: to is not a model item");
- return;
- }
-
- const int unresolvedFlags = fromIt->flags;
- const int resolvedFlags = toIt->flags;
- const int resolvedIndex = toIt.modelIndex();
- void * const resolvedList = toIt->list;
-
- QQmlDelegateModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
- cacheItem->groups &= ~Compositor::UnresolvedFlag;
-
- if (toIt.cacheIndex > fromIt.cacheIndex)
- toIt.decrementIndexes(1, unresolvedFlags);
- if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
- from += 1;
-
- model->itemsMoved(
- QVector<Compositor::Remove>(1, Compositor::Remove(fromIt, 1, unresolvedFlags, 0)),
- QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, unresolvedFlags, 0)));
- model->itemsInserted(
- QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag)));
- toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
- model->itemsRemoved(QVector<Compositor::Remove>(1, Compositor::Remove(toIt, 1, resolvedFlags)));
-
- model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
- model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
-
- if (resolvedFlags & Compositor::CacheFlag)
- model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
-
- Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
-
- if (!cacheItem->isReferenced()) {
- Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
- model->m_cache.removeAt(toIt.cacheIndex);
- model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
- delete cacheItem;
- Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
- } else {
- cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
- if (cacheItem->attached)
- cacheItem->attached->emitUnresolvedChanged();
- }
-
- model->emitChanges();
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::remove(int index, int count)
-
- Removes \a count items starting at \a index from the group.
-*/
-
-void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
-
- if (args->length() == 0)
- return;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (!d->parseIndex(v, &index, &group)) {
- qmlWarning(this) << tr("remove: invalid index");
- return;
- }
-
- if (++i < args->length()) {
- v = (*args)[i];
- if (v->isNumber())
- count = v->toInt32();
- }
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("remove: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("remove: invalid count");
- } else {
- model->removeGroups(it, count, d->group, 1 << d->group);
- }
- }
-}
-
-bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
-{
- if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
- return false;
-
- if (args->length() < 2)
- return false;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (!parseIndex(v, index, group))
- return false;
-
- v = (*args)[++i];
- if (v->isNumber()) {
- *count = v->toInt32();
-
- if (++i == args->length())
- return false;
- v = (*args)[i];
- }
-
- *groups = QQmlDelegateModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
-
- return true;
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::addGroups(int index, int count, stringlist groups)
-
- Adds \a count items starting at \a index to \a groups.
-*/
-
-void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("addGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("addGroups: invalid count");
- } else {
- model->addGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::removeGroups(int index, int count, stringlist groups)
-
- Removes \a count items starting at \a index from \a groups.
-*/
-
-void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("removeGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("removeGroups: invalid count");
- } else {
- model->removeGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
-
- Sets the \a groups \a count items starting at \a index belong to.
-*/
-
-void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("setGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("setGroups: invalid count");
- } else {
- model->setGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
-
- Sets the \a groups \a count items starting at \a index belong to.
-*/
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::move(var from, var to, int count)
-
- Moves \a count at \a from in a group \a to a new position.
-
- \note The DelegateModel acts as a proxy model: it holds the delegates in a
- different order than the \l{dm-model-property}{underlying model} has them.
- Any subsequent changes to the underlying model will not undo whatever
- reordering you have done via this function.
-*/
-
-void QQmlDelegateModelGroup::move(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
-
- if (args->length() < 2)
- return;
-
- Compositor::Group fromGroup = d->group;
- Compositor::Group toGroup = d->group;
- int from = -1;
- int to = -1;
- int count = 1;
-
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (!d->parseIndex(v, &from, &fromGroup)) {
- qmlWarning(this) << tr("move: invalid from index");
- return;
- }
-
- v = (*args)[1];
- if (!d->parseIndex(v, &to, &toGroup)) {
- qmlWarning(this) << tr("move: invalid to index");
- return;
- }
-
- if (args->length() > 2) {
- v = (*args)[2];
- if (v->isNumber())
- count = v->toInt32();
- }
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- if (count < 0) {
- qmlWarning(this) << tr("move: invalid count");
- } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
- qmlWarning(this) << tr("move: from index out of range");
- } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
- qmlWarning(this) << tr("move: to index out of range");
- } else if (count > 0) {
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
-
- model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
- model->itemsMoved(removes, inserts);
- model->emitChanges();
- }
-
-}
-
-/*!
- \qmlsignal QtQml.Models::DelegateModelGroup::changed(array removed, array inserted)
-
- This signal is emitted when items have been removed from or inserted into the group.
-
- Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
- item inserted or removed and a \e count of the number of consecutive items inserted or removed.
-
- Each index is adjusted for previous changes with all removed items preceding any inserted
- items.
-
- The corresponding handler is \c onChanged.
-*/
-
-//============================================================================
-
-QQmlPartsModel::QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent)
- : QQmlInstanceModel(*new QObjectPrivate, parent)
- , m_model(model)
- , m_part(part)
- , m_compositorGroup(Compositor::Cache)
- , m_inheritGroup(true)
-{
- QQmlDelegateModelPrivate *d = QQmlDelegateModelPrivate::get(m_model);
- if (d->m_cacheMetaType) {
- QQmlDelegateModelGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
- m_compositorGroup = Compositor::Default;
- } else {
- d->m_pendingParts.insert(this);
- }
-}
-
-QQmlPartsModel::~QQmlPartsModel()
-{
-}
-
-QString QQmlPartsModel::filterGroup() const
-{
- if (m_inheritGroup)
- return m_model->filterGroup();
- return m_filterGroup;
-}
-
-void QQmlPartsModel::setFilterGroup(const QString &group)
-{
- if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) {
- qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
- return;
- }
-
- if (m_filterGroup != group || m_inheritGroup) {
- m_filterGroup = group;
- m_inheritGroup = false;
- updateFilterGroup();
-
- emit filterGroupChanged();
- }
-}
-
-void QQmlPartsModel::resetFilterGroup()
-{
- if (!m_inheritGroup) {
- m_inheritGroup = true;
- updateFilterGroup();
- emit filterGroupChanged();
- }
-}
-
-void QQmlPartsModel::updateFilterGroup()
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- if (!model->m_cacheMetaType)
- return;
-
- if (m_inheritGroup) {
- if (m_filterGroup == model->m_filterGroup)
- return;
- m_filterGroup = model->m_filterGroup;
- }
-
- QQmlListCompositor::Group previousGroup = m_compositorGroup;
- m_compositorGroup = Compositor::Default;
- QQmlDelegateModelGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
- for (int i = 1; i < model->m_groupCount; ++i) {
- if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
- m_compositorGroup = Compositor::Group(i);
- break;
- }
- }
-
- QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
- if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Change> removes;
- QVector<QQmlChangeSet::Change> inserts;
- model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
-
- QQmlChangeSet changeSet;
- changeSet.move(removes, inserts);
- if (!changeSet.isEmpty())
- emit modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit countChanged();
- }
-}
-
-void QQmlPartsModel::updateFilterGroup(
- Compositor::Group group, const QQmlChangeSet &changeSet)
-{
- if (!m_inheritGroup)
- return;
-
- m_compositorGroup = group;
- QQmlDelegateModelGroupPrivate::get(QQmlDelegateModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
-
- if (!changeSet.isEmpty())
- emit modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit countChanged();
-
- emit filterGroupChanged();
-}
-
-int QQmlPartsModel::count() const
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- return model->m_delegate
- ? model->m_compositor.count(m_compositorGroup)
- : 0;
-}
-
-bool QQmlPartsModel::isValid() const
-{
- return m_model->isValid();
-}
-
-QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
-
- if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
- qWarning() << "DelegateModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
- return nullptr;
- }
-
- QObject *object = model->object(m_compositorGroup, index, incubationMode);
-
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
- QObject *part = package->part(m_part);
- if (!part)
- return nullptr;
- m_packaged.insertMulti(part, package);
- return part;
- }
-
- model->release(object);
- if (!model->m_delegateValidated) {
- if (object)
- qmlWarning(model->m_delegate) << tr("Delegate component must be Package type.");
- model->m_delegateValidated = true;
- }
-
- return nullptr;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item)
-{
- QQmlInstanceModel::ReleaseFlags flags = nullptr;
-
- QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
- if (it != m_packaged.end()) {
- QQuickPackage *package = *it;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- flags = model->release(package);
- m_packaged.erase(it);
- if (!m_packaged.contains(item))
- flags &= ~Referenced;
- if (flags & Destroyed)
- QQmlDelegateModelPrivate::get(m_model)->emitDestroyingPackage(package);
- }
- return flags;
-}
-
-QVariant QQmlPartsModel::variantValue(int index, const QString &role)
-{
- return QQmlDelegateModelPrivate::get(m_model)->variantValue(m_compositorGroup, index, role);
-}
-
-void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &roles)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
- m_watchedRoles = roles;
-}
-
-QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- Compositor::iterator it = model->m_compositor.find(model->m_compositorGroup, index);
- if (!it->inCache())
- return QQmlIncubator::Null;
-
- if (auto incubationTask = model->m_cache.at(it.cacheIndex)->incubationTask)
- return incubationTask->status();
-
- return QQmlIncubator::Ready;
-}
-
-int QQmlPartsModel::indexOf(QObject *item, QObject *) const
-{
- QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
- if (it != m_packaged.end()) {
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(*it))
- return cacheItem->groupIndex(m_compositorGroup);
- }
- return -1;
-}
-
-void QQmlPartsModel::createdPackage(int index, QQuickPackage *package)
-{
- emit createdItem(index, package->part(m_part));
-}
-
-void QQmlPartsModel::initPackage(int index, QQuickPackage *package)
-{
- if (m_modelUpdatePending)
- m_pendingPackageInitializations << index;
- else
- emit initItem(index, package->part(m_part));
-}
-
-void QQmlPartsModel::destroyingPackage(QQuickPackage *package)
-{
- QObject *item = package->part(m_part);
- Q_ASSERT(!m_packaged.contains(item));
- emit destroyingItem(item);
-}
-
-void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- m_modelUpdatePending = false;
- emit modelUpdated(changeSet, reset);
- if (changeSet.difference() != 0)
- emit countChanged();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- QVector<int> pendingPackageInitializations;
- qSwap(pendingPackageInitializations, m_pendingPackageInitializations);
- for (int index : pendingPackageInitializations) {
- if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup))
- continue;
- QObject *object = model->object(m_compositorGroup, index, QQmlIncubator::Asynchronous);
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emit initItem(index, package->part(m_part));
- model->release(object);
- }
-}
-
-//============================================================================
-
-struct QQmlDelegateModelGroupChange : QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelGroupChange, QV4::Object)
-
- static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
- return e->memoryManager->allocate<QQmlDelegateModelGroupChange>();
- }
-
- static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- return QV4::Encode(that->d()->change.index);
- }
- static QV4::ReturnedValue method_get_count(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- return QV4::Encode(that->d()->change.count);
- }
- static QV4::ReturnedValue method_get_moveId(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- if (that->d()->change.moveId < 0)
- RETURN_UNDEFINED();
- return QV4::Encode(that->d()->change.moveId);
- }
-};
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChange);
-
-struct QQmlDelegateModelGroupChangeArray : public QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelGroupChangeArray, QV4::Object)
- V4_NEEDS_DESTROY
-public:
- static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
- {
- return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes);
- }
-
- quint32 count() const { return d()->changes->count(); }
- const QQmlChangeSet::Change &at(int index) const { return d()->changes->at(index); }
-
- static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
- {
- if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>());
- QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine();
- QV4::Scope scope(v4);
- QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<const QQmlDelegateModelGroupChangeArray *>(m));
-
- if (index >= array->count()) {
- if (hasProperty)
- *hasProperty = false;
- return QV4::Value::undefinedValue().asReturnedValue();
- }
-
- const QQmlChangeSet::Change &change = array->at(index);
-
- QV4::ScopedObject changeProto(scope, engineData(v4)->changeProto.value());
- QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4));
- object->setPrototypeOf(changeProto);
- object->d()->change = change;
-
- if (hasProperty)
- *hasProperty = true;
- return object.asReturnedValue();
- }
-
- Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>());
- const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m);
-
- if (id == array->engine()->id_length()->propertyKey()) {
- if (hasProperty)
- *hasProperty = true;
- return QV4::Encode(array->count());
- }
-
- return Object::virtualGet(m, id, receiver, hasProperty);
- }
-};
-
-void QV4::Heap::QQmlDelegateModelGroupChangeArray::init(const QVector<QQmlChangeSet::Change> &changes)
-{
- Object::init();
- this->changes = new QVector<QQmlChangeSet::Change>(changes);
- QV4::Scope scope(internalClass->engine);
- QV4::ScopedObject o(scope, this);
- o->setArrayType(QV4::Heap::ArrayData::Custom);
-}
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChangeArray);
-
-QQmlDelegateModelEngineData::QQmlDelegateModelEngineData(QV4::ExecutionEngine *v4)
-{
- QV4::Scope scope(v4);
-
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), QQmlDelegateModelGroupChange::method_get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("count"), QQmlDelegateModelGroupChange::method_get_count, nullptr);
- proto->defineAccessorProperty(QStringLiteral("moveId"), QQmlDelegateModelGroupChange::method_get_moveId, nullptr);
- changeProto.set(v4, proto);
-}
-
-QQmlDelegateModelEngineData::~QQmlDelegateModelEngineData()
-{
-}
-
-QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV4::ExecutionEngine *v4,
- const QVector<QQmlChangeSet::Change> &changes)
-{
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, QQmlDelegateModelGroupChangeArray::create(v4, changes));
- return o.asReturnedValue();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmldelegatemodel_p.cpp"
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
deleted file mode 100644
index 2684162514..0000000000
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDATAMODEL_P_H
-#define QQMLDATAMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmllistcompositor_p.h>
-#include <private/qqmlobjectmodel_p.h>
-#include <private/qqmlincubator_p.h>
-
-#include <QtCore/qabstractitemmodel.h>
-#include <QtCore/qstringlist.h>
-
-#include <private/qqmlglobal_p.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-class QQmlChangeSet;
-class QQuickPackage;
-class QQmlV4Function;
-class QQmlDelegateModelGroup;
-class QQmlDelegateModelAttached;
-class QQmlDelegateModelPrivate;
-
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQmlDelegateModel)
-
- Q_PROPERTY(QVariant model READ model WRITE setModel)
- Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate)
- Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
- Q_PROPERTY(QQmlDelegateModelGroup *items READ items CONSTANT) //TODO : worth renaming?
- Q_PROPERTY(QQmlDelegateModelGroup *persistedItems READ persistedItems CONSTANT)
- Q_PROPERTY(QQmlListProperty<QQmlDelegateModelGroup> groups READ groups CONSTANT)
- Q_PROPERTY(QObject *parts READ parts CONSTANT)
- Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
- Q_INTERFACES(QQmlParserStatus)
-public:
- QQmlDelegateModel();
- QQmlDelegateModel(QQmlContext *, QObject *parent=nullptr);
- ~QQmlDelegateModel();
-
- void classBegin() override;
- void componentComplete() override;
-
- QVariant model() const;
- void setModel(const QVariant &);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *);
-
- QVariant rootIndex() const;
- void setRootIndex(const QVariant &root);
-
- Q_INVOKABLE QVariant modelIndex(int idx) const;
- Q_INVOKABLE QVariant parentModelIndex() const;
-
- int count() const override;
- bool isValid() const override { return delegate() != nullptr; }
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
- void cancel(int index) override;
- QVariant variantValue(int index, const QString &role) override;
- void setWatchedRoles(const QList<QByteArray> &roles) override;
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *object, QObject *objectContext) const override;
-
- QString filterGroup() const;
- void setFilterGroup(const QString &group);
- void resetFilterGroup();
-
- QQmlDelegateModelGroup *items();
- QQmlDelegateModelGroup *persistedItems();
- QQmlListProperty<QQmlDelegateModelGroup> groups();
- QObject *parts();
-
- const QAbstractItemModel *abstractItemModel() const override;
-
- bool event(QEvent *) override;
-
- static QQmlDelegateModelAttached *qmlAttachedProperties(QObject *obj);
-
-Q_SIGNALS:
- void filterGroupChanged();
- void defaultGroupsChanged();
- void rootIndexChanged();
-
-private Q_SLOTS:
- void _q_itemsChanged(int index, int count, const QVector<int> &roles);
- void _q_itemsInserted(int index, int count);
- void _q_itemsRemoved(int index, int count);
- void _q_itemsMoved(int from, int to, int count);
- void _q_modelReset();
- void _q_rowsInserted(const QModelIndex &,int,int);
- void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end);
- void _q_rowsRemoved(const QModelIndex &,int,int);
- void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
- void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &);
- void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
-
-private:
- bool isDescendantOf(const QPersistentModelIndex &desc, const QList<QPersistentModelIndex> &parents) const;
-
- Q_DISABLE_COPY(QQmlDelegateModel)
-};
-
-class QQmlDelegateModelGroupPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
- Q_PROPERTY(bool includeByDefault READ defaultInclude WRITE setDefaultInclude NOTIFY defaultIncludeChanged)
-public:
- QQmlDelegateModelGroup(QObject *parent = nullptr);
- QQmlDelegateModelGroup(const QString &name, QQmlDelegateModel *model, int compositorType, QObject *parent = nullptr);
- ~QQmlDelegateModelGroup();
-
- QString name() const;
- void setName(const QString &name);
-
- int count() const;
-
- bool defaultInclude() const;
- void setDefaultInclude(bool include);
-
- Q_INVOKABLE QJSValue get(int index);
-
-public Q_SLOTS:
- void insert(QQmlV4Function *);
- void create(QQmlV4Function *);
- void resolve(QQmlV4Function *);
- void remove(QQmlV4Function *);
- void addGroups(QQmlV4Function *);
- void removeGroups(QQmlV4Function *);
- void setGroups(QQmlV4Function *);
- void move(QQmlV4Function *);
-
-Q_SIGNALS:
- void countChanged();
- void nameChanged();
- void defaultIncludeChanged();
- void changed(const QJSValue &removed, const QJSValue &inserted);
-private:
- Q_DECLARE_PRIVATE(QQmlDelegateModelGroup)
-};
-
-class QQmlDelegateModelItem;
-class QQmlDelegateModelAttachedMetaObject;
-class QQmlDelegateModelAttached : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QQmlDelegateModel *model READ model CONSTANT)
- Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged)
- Q_PROPERTY(bool isUnresolved READ isUnresolved NOTIFY unresolvedChanged)
-public:
- QQmlDelegateModelAttached(QObject *parent);
- QQmlDelegateModelAttached(QQmlDelegateModelItem *cacheItem, QObject *parent);
- ~QQmlDelegateModelAttached() {}
-
- void resetCurrentIndex();
- void setCacheItem(QQmlDelegateModelItem *item);
-
- QQmlDelegateModel *model() const;
-
- QStringList groups() const;
- void setGroups(const QStringList &groups);
-
- bool isUnresolved() const;
-
- void emitChanges();
-
- void emitUnresolvedChanged() { Q_EMIT unresolvedChanged(); }
-
-Q_SIGNALS:
- void groupsChanged();
- void unresolvedChanged();
-
-public:
- QQmlDelegateModelItem *m_cacheItem;
- int m_previousGroups;
- int m_currentIndex[QQmlListCompositor::MaximumGroupCount];
- int m_previousIndex[QQmlListCompositor::MaximumGroupCount];
-
- friend class QQmlDelegateModelAttachedMetaObject;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlDelegateModel)
-QML_DECLARE_TYPEINFO(QQmlDelegateModel, QML_HAS_ATTACHED_PROPERTIES)
-QML_DECLARE_TYPE(QQmlDelegateModelGroup)
-
-#endif // QQMLDATAMODEL_P_H
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
deleted file mode 100644
index 7f10bbf370..0000000000
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDATAMODEL_P_P_H
-#define QQMLDATAMODEL_P_P_H
-
-#include "qqmldelegatemodel_p.h"
-#include <private/qv4qobjectwrapper_p.h>
-
-#include <QtQml/qqmlcontext.h>
-#include <QtQml/qqmlincubator.h>
-
-#include <private/qqmladaptormodel_p.h>
-#include <private/qqmlopenmetaobject_p.h>
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-typedef QQmlListCompositor Compositor;
-
-class QQmlDelegateModelAttachedMetaObject;
-class QQmlAbstractDelegateComponent;
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
-{
-public:
- QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
- ~QQmlDelegateModelItemMetaType();
-
- void initializeMetaObject();
- void initializePrototype();
-
- int parseGroups(const QStringList &groupNames) const;
- int parseGroups(const QV4::Value &groupNames) const;
-
- QPointer<QQmlDelegateModel> model;
- const int groupCount;
- QV4::ExecutionEngine * const v4Engine;
- QQmlDelegateModelAttachedMetaObject *metaObject;
- const QStringList groupNames;
- QV4::PersistentValue modelItemProto;
-};
-
-class QQmlAdaptorModel;
-class QQDMIncubationTask;
-
-class QQmlDelegateModelItem : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged)
- Q_PROPERTY(int row READ modelRow NOTIFY rowChanged REVISION 12)
- Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12)
- Q_PROPERTY(QObject *model READ modelObject CONSTANT)
-public:
- QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor, int modelIndex,
- int row, int column);
- ~QQmlDelegateModelItem();
-
- void referenceObject() { ++objectRef; }
- bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
- bool isObjectReferenced() const { return objectRef != 0 || (groups & Compositor::PersistedFlag); }
- void childContextObjectDestroyed(QObject *childContextObject);
-
- bool isReferenced() const {
- return scriptRef
- || incubationTask
- || ((groups & Compositor::UnresolvedFlag) && (groups & Compositor::GroupMask));
- }
-
- void Dispose();
-
- QObject *modelObject() { return this; }
-
- void destroyObject();
-
- static QQmlDelegateModelItem *dataForObject(QObject *object);
-
- int groupIndex(Compositor::Group group);
-
- int modelRow() const { return row; }
- int modelColumn() const { return column; }
- int modelIndex() const { return index; }
- virtual void setModelIndex(int idx, int newRow, int newColumn);
-
- virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(v4, this); }
-
- virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
- virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
-
- static QV4::ReturnedValue get_model(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue get_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue set_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
- static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
- static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
-
- QV4::ExecutionEngine *v4;
- QQmlDelegateModelItemMetaType * const metaType;
- QQmlContextDataRef contextData;
- QPointer<QObject> object;
- QPointer<QQmlDelegateModelAttached> attached;
- QQDMIncubationTask *incubationTask;
- QQmlComponent *delegate;
- int poolTime;
- int objectRef;
- int scriptRef;
- int groups;
- int index;
-
-Q_SIGNALS:
- void modelIndexChanged();
- Q_REVISION(12) void rowChanged();
- Q_REVISION(12) void columnChanged();
-
-protected:
- void objectDestroyed(QObject *);
- int row;
- int column;
-};
-
-namespace QV4 {
-namespace Heap {
-struct QQmlDelegateModelItemObject : Object {
- inline void init(QQmlDelegateModelItem *item);
- void destroy();
- QQmlDelegateModelItem *item;
-};
-
-}
-}
-
-struct QQmlDelegateModelItemObject : QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelItemObject, QV4::Object)
- V4_NEEDS_DESTROY
-};
-
-void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
-{
- Object::init();
- this->item = item;
-}
-
-
-
-class QQmlDelegateModelPrivate;
-class QQDMIncubationTask : public QQmlIncubator
-{
-public:
- QQDMIncubationTask(QQmlDelegateModelPrivate *l, IncubationMode mode)
- : QQmlIncubator(mode)
- , incubating(nullptr)
- , vdm(l) {}
-
- void statusChanged(Status) override;
- void setInitialState(QObject *) override;
-
- QQmlDelegateModelItem *incubating = nullptr;
- QQmlDelegateModelPrivate *vdm = nullptr;
- int index[QQmlListCompositor::MaximumGroupCount];
-};
-
-
-class QQmlDelegateModelGroupEmitter
-{
-public:
- virtual ~QQmlDelegateModelGroupEmitter() {}
- virtual void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) = 0;
- virtual void createdPackage(int, QQuickPackage *) {}
- virtual void initPackage(int, QQuickPackage *) {}
- virtual void destroyingPackage(QQuickPackage *) {}
-
- QIntrusiveListNode emitterNode;
-};
-
-typedef QIntrusiveList<QQmlDelegateModelGroupEmitter, &QQmlDelegateModelGroupEmitter::emitterNode> QQmlDelegateModelGroupEmitterList;
-
-class QQmlDelegateModelGroupPrivate : public QObjectPrivate
-{
-public:
- Q_DECLARE_PUBLIC(QQmlDelegateModelGroup)
-
- QQmlDelegateModelGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
-
- static QQmlDelegateModelGroupPrivate *get(QQmlDelegateModelGroup *group) {
- return static_cast<QQmlDelegateModelGroupPrivate *>(QObjectPrivate::get(group)); }
-
- void setModel(QQmlDelegateModel *model, Compositor::Group group);
- bool isChangedConnected();
- void emitChanges(QV4::ExecutionEngine *engine);
- void emitModelUpdated(bool reset);
-
- void createdPackage(int index, QQuickPackage *package);
- void initPackage(int index, QQuickPackage *package);
- void destroyingPackage(QQuickPackage *package);
-
- bool parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const;
- bool parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const;
-
- Compositor::Group group;
- QPointer<QQmlDelegateModel> model;
- QQmlDelegateModelGroupEmitterList emitters;
- QQmlChangeSet changeSet;
- QString name;
- bool defaultInclude;
-};
-
-class QQmlDelegateModelParts;
-
-class QQmlDelegateModelPrivate : public QObjectPrivate, public QQmlDelegateModelGroupEmitter
-{
- Q_DECLARE_PUBLIC(QQmlDelegateModel)
-public:
- QQmlDelegateModelPrivate(QQmlContext *);
- ~QQmlDelegateModelPrivate();
-
- static QQmlDelegateModelPrivate *get(QQmlDelegateModel *m) {
- return static_cast<QQmlDelegateModelPrivate *>(QObjectPrivate::get(m));
- }
-
- void init();
- void connectModel(QQmlAdaptorModel *model);
- void connectToAbstractItemModel();
- void disconnectFromAbstractItemModel();
-
- void requestMoreIfNecessary();
- QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
- QQmlDelegateModel::ReleaseFlags release(QObject *object);
- QVariant variantValue(Compositor::Group group, int index, const QString &name);
- void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
- void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
- void emitCreatedItem(QQDMIncubationTask *incubationTask, QObject *item) {
- Q_EMIT q_func()->createdItem(incubationTask->index[m_compositorGroup], item); }
- void emitInitItem(QQDMIncubationTask *incubationTask, QObject *item) {
- Q_EMIT q_func()->initItem(incubationTask->index[m_compositorGroup], item); }
- void emitDestroyingPackage(QQuickPackage *package);
- void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(item); }
- void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it);
- void removeCacheItem(QQmlDelegateModelItem *cacheItem);
-
- void updateFilterGroup();
-
- void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
- void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
- void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
-
- void itemsInserted(
- const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
- void itemsInserted(const QVector<Compositor::Insert> &inserts);
- void itemsRemoved(
- const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
- void itemsRemoved(const QVector<Compositor::Remove> &removes);
- void itemsMoved(
- const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts);
- void itemsChanged(const QVector<Compositor::Change> &changes);
- void emitChanges();
- void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
- void delegateChanged(bool add = true, bool remove = true);
-
- bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
-
- int adaptorModelCount() const;
-
- static void group_append(QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group);
- static int group_count(QQmlListProperty<QQmlDelegateModelGroup> *property);
- static QQmlDelegateModelGroup *group_at(QQmlListProperty<QQmlDelegateModelGroup> *property, int index);
-
- void releaseIncubator(QQDMIncubationTask *incubationTask);
- void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status);
- void setInitialState(QQDMIncubationTask *incubationTask, QObject *o);
-
- QQmlAdaptorModel m_adaptorModel;
- QQmlListCompositor m_compositor;
- QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
- QQmlAbstractDelegateComponent *m_delegateChooser;
- QMetaObject::Connection m_delegateChooserChanged;
- QQmlDelegateModelItemMetaType *m_cacheMetaType;
- QPointer<QQmlContext> m_context;
- QQmlDelegateModelParts *m_parts;
- QQmlDelegateModelGroupEmitterList m_pendingParts;
-
- QList<QQmlDelegateModelItem *> m_cache;
- QList<QQDMIncubationTask *> m_finishedIncubating;
- QList<QByteArray> m_watchedRoles;
-
- QString m_filterGroup;
-
- int m_count;
- int m_groupCount;
-
- QQmlListCompositor::Group m_compositorGroup;
- bool m_complete : 1;
- bool m_delegateValidated : 1;
- bool m_reset : 1;
- bool m_transaction : 1;
- bool m_incubatorCleanupScheduled : 1;
- bool m_waitingToFetchMore : 1;
-
- union {
- struct {
- QQmlDelegateModelGroup *m_cacheItems;
- QQmlDelegateModelGroup *m_items;
- QQmlDelegateModelGroup *m_persistedItems;
- };
- QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
- };
-};
-
-class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
-{
- Q_OBJECT
- Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
-public:
- QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent = nullptr);
- ~QQmlPartsModel();
-
- QString filterGroup() const;
- void setFilterGroup(const QString &group);
- void resetFilterGroup();
- void updateFilterGroup();
- void updateFilterGroup(Compositor::Group group, const QQmlChangeSet &changeSet);
-
- int count() const override;
- bool isValid() const override;
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *item) override;
- QVariant variantValue(int index, const QString &role) override;
- QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
- void setWatchedRoles(const QList<QByteArray> &roles) override;
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *item, QObject *objectContext) const override;
-
- void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
-
- void createdPackage(int index, QQuickPackage *package) override;
- void initPackage(int index, QQuickPackage *package) override;
- void destroyingPackage(QQuickPackage *package) override;
-
-Q_SIGNALS:
- void filterGroupChanged();
-
-private:
- QQmlDelegateModel *m_model;
- QHash<QObject *, QQuickPackage *> m_packaged;
- QString m_part;
- QString m_filterGroup;
- QList<QByteArray> m_watchedRoles;
- QVector<int> m_pendingPackageInitializations; // vector holds model indices
- Compositor::Group m_compositorGroup;
- bool m_inheritGroup;
- bool m_modelUpdatePending = true;
-};
-
-class QMetaPropertyBuilder;
-
-class QQmlDelegateModelPartsMetaObject : public QQmlOpenMetaObject
-{
-public:
- QQmlDelegateModelPartsMetaObject(QObject *parent)
- : QQmlOpenMetaObject(parent) {}
-
- void propertyCreated(int, QMetaPropertyBuilder &) override;
- QVariant initialValue(int) override;
-};
-
-class QQmlDelegateModelParts : public QObject
-{
-Q_OBJECT
-public:
- QQmlDelegateModelParts(QQmlDelegateModel *parent);
-
- QQmlDelegateModel *model;
- QList<QQmlPartsModel *> models;
-};
-
-class QQmlDelegateModelAttachedMetaObject : public QAbstractDynamicMetaObject, public QQmlRefCount
-{
-public:
- QQmlDelegateModelAttachedMetaObject(
- QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject);
- ~QQmlDelegateModelAttachedMetaObject();
-
- void objectDestroyed(QObject *) override;
- int metaCall(QObject *, QMetaObject::Call, int _id, void **) override;
-
-private:
- QQmlDelegateModelItemMetaType * const metaType;
- QMetaObject * const metaObject;
- const int memberPropertyOffset;
- const int indexPropertyOffset;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
deleted file mode 100644
index a23ec0f2b4..0000000000
--- a/src/qml/types/qqmlinstantiator.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlinstantiator_p.h"
-#include "qqmlinstantiator_p_p.h"
-#include <QtQml/QQmlContext>
-#include <QtQml/QQmlComponent>
-#include <QtQml/QQmlInfo>
-#include <QtQml/QQmlError>
-#include <QtQml/private/qqmlobjectmodel_p.h>
-#if QT_CONFIG(qml_delegate_model)
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-QQmlInstantiatorPrivate::QQmlInstantiatorPrivate()
- : componentComplete(true)
- , effectiveReset(false)
- , active(true)
- , async(false)
-#if QT_CONFIG(qml_delegate_model)
- , ownModel(false)
-#endif
- , requestedIndex(-1)
- , model(QVariant(1))
- , instanceModel(nullptr)
- , delegate(nullptr)
-{
-}
-
-QQmlInstantiatorPrivate::~QQmlInstantiatorPrivate()
-{
- qDeleteAll(objects);
-}
-
-void QQmlInstantiatorPrivate::clear()
-{
- Q_Q(QQmlInstantiator);
- if (!instanceModel)
- return;
- if (!objects.count())
- return;
-
- for (int i=0; i < objects.count(); i++) {
- q->objectRemoved(i, objects[i]);
- instanceModel->release(objects[i]);
- }
- objects.clear();
- q->objectChanged();
-}
-
-QObject *QQmlInstantiatorPrivate::modelObject(int index, bool async)
-{
- requestedIndex = index;
- QObject *o = instanceModel->object(index, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
- requestedIndex = -1;
- return o;
-}
-
-
-void QQmlInstantiatorPrivate::regenerate()
-{
- Q_Q(QQmlInstantiator);
- if (!componentComplete)
- return;
-
- int prevCount = q->count();
-
- clear();
-
- if (!active || !instanceModel || !instanceModel->count() || !instanceModel->isValid()) {
- if (prevCount)
- q->countChanged();
- return;
- }
-
- for (int i = 0; i < instanceModel->count(); i++) {
- QObject *object = modelObject(i, async);
- // If the item was already created we won't get a createdItem
- if (object)
- _q_createdItem(i, object);
- }
- if (q->count() != prevCount)
- q->countChanged();
-}
-
-void QQmlInstantiatorPrivate::_q_createdItem(int idx, QObject* item)
-{
- Q_Q(QQmlInstantiator);
- if (objects.contains(item)) //Case when it was created synchronously in regenerate
- return;
- if (requestedIndex != idx) // Asynchronous creation, reference the object
- (void)instanceModel->object(idx);
- item->setParent(q);
- if (objects.size() < idx + 1) {
- int modelCount = instanceModel->count();
- if (objects.capacity() < modelCount)
- objects.reserve(modelCount);
- objects.resize(idx + 1);
- }
- if (QObject *o = objects.at(idx))
- instanceModel->release(o);
- objects.replace(idx, item);
- if (objects.count() == 1)
- q->objectChanged();
- q->objectAdded(idx, item);
-}
-
-void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- Q_Q(QQmlInstantiator);
-
- if (!componentComplete || effectiveReset)
- return;
-
- if (reset) {
- regenerate();
- if (changeSet.difference() != 0)
- q->countChanged();
- return;
- }
-
- int difference = 0;
- QHash<int, QVector<QPointer<QObject> > > moved;
- const QVector<QQmlChangeSet::Change> &removes = changeSet.removes();
- for (const QQmlChangeSet::Change &remove : removes) {
- int index = qMin(remove.index, objects.count());
- int count = qMin(remove.index + remove.count, objects.count()) - index;
- if (remove.isMove()) {
- moved.insert(remove.moveId, objects.mid(index, count));
- objects.erase(
- objects.begin() + index,
- objects.begin() + index + count);
- } else while (count--) {
- QObject *obj = objects.at(index);
- objects.remove(index);
- q->objectRemoved(index, obj);
- if (obj)
- instanceModel->release(obj);
- }
-
- difference -= remove.count;
- }
-
- const QVector<QQmlChangeSet::Change> &inserts = changeSet.inserts();
- for (const QQmlChangeSet::Change &insert : inserts) {
- int index = qMin(insert.index, objects.count());
- if (insert.isMove()) {
- QVector<QPointer<QObject> > movedObjects = moved.value(insert.moveId);
- objects = objects.mid(0, index) + movedObjects + objects.mid(index);
- } else {
- if (insert.index <= objects.size())
- objects.insert(insert.index, insert.count, nullptr);
- for (int i = 0; i < insert.count; ++i) {
- int modelIndex = index + i;
- QObject* obj = modelObject(modelIndex, async);
- if (obj)
- _q_createdItem(modelIndex, obj);
- }
- }
- difference += insert.count;
- }
-
- if (difference != 0)
- q->countChanged();
-}
-
-#if QT_CONFIG(qml_delegate_model)
-void QQmlInstantiatorPrivate::makeModel()
-{
- Q_Q(QQmlInstantiator);
- QQmlDelegateModel* delegateModel = new QQmlDelegateModel(qmlContext(q), q);
- instanceModel = delegateModel;
- ownModel = true;
- delegateModel->setDelegate(delegate);
- delegateModel->classBegin(); //Pretend it was made in QML
- if (componentComplete)
- delegateModel->componentComplete();
-}
-#endif
-
-
-/*!
- \qmltype Instantiator
- \instantiates QQmlInstantiator
- \inqmlmodule QtQml
- \brief Dynamically creates objects.
-
- A Instantiator can be used to control the dynamic creation of objects, or to dynamically
- create multiple objects from a template.
-
- The Instantiator element will manage the objects it creates. Those objects are parented to the
- Instantiator and can also be deleted by the Instantiator if the Instantiator's properties change. Objects
- can also be destroyed dynamically through other means, and the Instantiator will not recreate
- them unless the properties of the Instantiator change.
-
-*/
-QQmlInstantiator::QQmlInstantiator(QObject *parent)
- : QObject(*(new QQmlInstantiatorPrivate), parent)
-{
-}
-
-QQmlInstantiator::~QQmlInstantiator()
-{
-}
-
-/*!
- \qmlsignal QtQml::Instantiator::objectAdded(int index, QtObject object)
-
- This signal is emitted when an object is added to the Instantiator. The \a index
- parameter holds the index which the object has been given, and the \a object
- parameter holds the \l QtObject that has been added.
-
- The corresponding handler is \c onObjectAdded.
-*/
-
-/*!
- \qmlsignal QtQml::Instantiator::objectRemoved(int index, QtObject object)
-
- This signal is emitted when an object is removed from the Instantiator. The \a index
- parameter holds the index which the object had been given, and the \a object
- parameter holds the \l QtObject that has been removed.
-
- Do not keep a reference to \a object if it was created by this Instantiator, as
- in these cases it will be deleted shortly after the signal is handled.
-
- The corresponding handler is \c onObjectRemoved.
-*/
-/*!
- \qmlproperty bool QtQml::Instantiator::active
-
- When active is true, and the delegate component is ready, the Instantiator will
- create objects according to the model. When active is false, no objects
- will be created and any previously created objects will be destroyed.
-
- Default is true.
-*/
-bool QQmlInstantiator::isActive() const
-{
- Q_D(const QQmlInstantiator);
- return d->active;
-}
-
-void QQmlInstantiator::setActive(bool newVal)
-{
- Q_D(QQmlInstantiator);
- if (newVal == d->active)
- return;
- d->active = newVal;
- emit activeChanged();
- d->regenerate();
-}
-
-/*!
- \qmlproperty bool QtQml::Instantiator::asynchronous
-
- When asynchronous is true the Instantiator will attempt to create objects
- asynchronously. This means that objects may not be available immediately,
- even if active is set to true.
-
- You can use the objectAdded signal to respond to items being created.
-
- Default is false.
-*/
-bool QQmlInstantiator::isAsync() const
-{
- Q_D(const QQmlInstantiator);
- return d->async;
-}
-
-void QQmlInstantiator::setAsync(bool newVal)
-{
- Q_D(QQmlInstantiator);
- if (newVal == d->async)
- return;
- d->async = newVal;
- emit asynchronousChanged();
-}
-
-
-/*!
- \qmlproperty int QtQml::Instantiator::count
-
- The number of objects the Instantiator is currently managing.
-*/
-
-int QQmlInstantiator::count() const
-{
- Q_D(const QQmlInstantiator);
- return d->objects.count();
-}
-
-/*!
- \qmlproperty QtQml::Component QtQml::Instantiator::delegate
- \default
-
- The component used to create all objects.
-
- Note that an extra variable, index, will be available inside instances of the
- delegate. This variable refers to the index of the instance inside the Instantiator,
- and can be used to obtain the object through the objectAt method of the Instantiator.
-
- If this property is changed, all instances using the old delegate will be destroyed
- and new instances will be created using the new delegate.
-*/
-QQmlComponent* QQmlInstantiator::delegate()
-{
- Q_D(QQmlInstantiator);
- return d->delegate;
-}
-
-void QQmlInstantiator::setDelegate(QQmlComponent* c)
-{
- Q_D(QQmlInstantiator);
- if (c == d->delegate)
- return;
-
- d->delegate = c;
- emit delegateChanged();
-
-#if QT_CONFIG(qml_delegate_model)
- if (!d->ownModel)
- return;
-
- if (QQmlDelegateModel *dModel = qobject_cast<QQmlDelegateModel*>(d->instanceModel))
- dModel->setDelegate(c);
- if (d->componentComplete)
- d->regenerate();
-#endif
-}
-
-/*!
- \qmlproperty variant QtQml::Instantiator::model
-
- This property can be set to any of the supported \l {qml-data-models}{data models}:
-
- \list
- \li A number that indicates the number of delegates to be created by the repeater
- \li A model (e.g. a ListModel item, or a QAbstractItemModel subclass)
- \li A string list
- \li An object list
- \endlist
-
- The type of model affects the properties that are exposed to the \l delegate.
-
- Default value is 1, which creates a single delegate instance.
-
- \sa {qml-data-models}{Data Models}
-*/
-
-QVariant QQmlInstantiator::model() const
-{
- Q_D(const QQmlInstantiator);
- return d->model;
-}
-
-void QQmlInstantiator::setModel(const QVariant &v)
-{
- Q_D(QQmlInstantiator);
- if (d->model == v)
- return;
-
- d->model = v;
- //Don't actually set model until componentComplete in case it wants to create its delegates immediately
- if (!d->componentComplete)
- return;
-
- QQmlInstanceModel *prevModel = d->instanceModel;
- QObject *object = qvariant_cast<QObject*>(v);
- QQmlInstanceModel *vim = nullptr;
- if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
-#if QT_CONFIG(qml_delegate_model)
- if (d->ownModel) {
- delete d->instanceModel;
- prevModel = nullptr;
- d->ownModel = false;
- }
-#endif
- d->instanceModel = vim;
-#if QT_CONFIG(qml_delegate_model)
- } else if (v != QVariant(0)){
- if (!d->ownModel)
- d->makeModel();
-
- if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel *>(d->instanceModel)) {
- d->effectiveReset = true;
- dataModel->setModel(v);
- d->effectiveReset = false;
- }
-#endif
- }
-
- if (d->instanceModel != prevModel) {
- if (prevModel) {
- disconnect(prevModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- disconnect(prevModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //disconnect(prevModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
- }
-
- if (d->instanceModel) {
- connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
- }
- }
-
- d->regenerate();
- emit modelChanged();
-}
-
-/*!
- \qmlproperty QtObject QtQml::Instantiator::object
-
- This is a reference to the first created object, intended as a convenience
- for the case where only one object has been created.
-*/
-QObject *QQmlInstantiator::object() const
-{
- Q_D(const QQmlInstantiator);
- if (d->objects.count())
- return d->objects[0];
- return nullptr;
-}
-
-/*!
- \qmlmethod QtObject QtQml::Instantiator::objectAt(int index)
-
- Returns a reference to the object with the given \a index.
-*/
-QObject *QQmlInstantiator::objectAt(int index) const
-{
- Q_D(const QQmlInstantiator);
- if (index >= 0 && index < d->objects.count())
- return d->objects[index];
- return nullptr;
-}
-
-/*!
- \internal
-*/
-void QQmlInstantiator::classBegin()
-{
- Q_D(QQmlInstantiator);
- d->componentComplete = false;
-}
-
-/*!
- \internal
-*/
-void QQmlInstantiator::componentComplete()
-{
- Q_D(QQmlInstantiator);
- d->componentComplete = true;
-#if QT_CONFIG(qml_delegate_model)
- if (d->ownModel) {
- static_cast<QQmlDelegateModel*>(d->instanceModel)->componentComplete();
- d->regenerate();
- } else
-#endif
- {
- QVariant realModel = d->model;
- d->model = QVariant(0);
- setModel(realModel); //If realModel == d->model this won't do anything, but that's fine since the model's 0
- //setModel calls regenerate
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlinstantiator_p.cpp"
diff --git a/src/qml/types/qqmlinstantiator_p.h b/src/qml/types/qqmlinstantiator_p.h
deleted file mode 100644
index ca371adc23..0000000000
--- a/src/qml/types/qqmlinstantiator_p.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANTIATOR_P_H
-#define QQMLINSTANTIATOR_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlInstantiatorPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
- Q_PROPERTY(bool asynchronous READ isAsync WRITE setAsync NOTIFY asynchronousChanged)
- Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
- Q_PROPERTY(QObject *object READ object NOTIFY objectChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
-
-public:
- QQmlInstantiator(QObject *parent = nullptr);
- ~QQmlInstantiator();
-
- bool isActive() const;
- void setActive(bool newVal);
-
- bool isAsync() const;
- void setAsync(bool newVal);
-
- int count() const;
-
- QQmlComponent* delegate();
- void setDelegate(QQmlComponent* c);
-
- QVariant model() const;
- void setModel(const QVariant &v);
-
- QObject *object() const;
-
- Q_INVOKABLE QObject *objectAt(int index) const;
-
- void classBegin() override;
- void componentComplete() override;
-
-Q_SIGNALS:
- void modelChanged();
- void delegateChanged();
- void countChanged();
- void objectChanged();
- void activeChanged();
- void asynchronousChanged();
-
- void objectAdded(int index, QObject* object);
- void objectRemoved(int index, QObject* object);
-
-private:
- Q_DISABLE_COPY(QQmlInstantiator)
- Q_DECLARE_PRIVATE(QQmlInstantiator)
- Q_PRIVATE_SLOT(d_func(), void _q_createdItem(int, QObject *))
- Q_PRIVATE_SLOT(d_func(), void _q_modelUpdated(const QQmlChangeSet &, bool))
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCREATOR_P_H
diff --git a/src/qml/types/qqmlinstantiator_p_p.h b/src/qml/types/qqmlinstantiator_p_p.h
deleted file mode 100644
index 4c76d5c689..0000000000
--- a/src/qml/types/qqmlinstantiator_p_p.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANTIATOR_P_P_H
-#define QQMLINSTANTIATOR_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qqmlinstantiator_p.h"
-#include <QObject>
-#include <private/qobject_p.h>
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlobjectmodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_PRIVATE_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QQmlInstantiator)
-
-public:
- QQmlInstantiatorPrivate();
- ~QQmlInstantiatorPrivate();
-
- void clear();
- void regenerate();
-#if QT_CONFIG(qml_delegate_model)
- void makeModel();
-#endif
- void _q_createdItem(int, QObject *);
- void _q_modelUpdated(const QQmlChangeSet &, bool);
- QObject *modelObject(int index, bool async);
-
- static QQmlInstantiatorPrivate *get(QQmlInstantiator *instantiator) { return instantiator->d_func(); }
- static const QQmlInstantiatorPrivate *get(const QQmlInstantiator *instantiator) { return instantiator->d_func(); }
-
- bool componentComplete:1;
- bool effectiveReset:1;
- bool active:1;
- bool async:1;
-#if QT_CONFIG(qml_delegate_model)
- bool ownModel:1;
-#endif
- int requestedIndex;
- QVariant model;
- QQmlInstanceModel *instanceModel;
- QQmlComponent *delegate;
- QVector<QPointer<QObject> > objects;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCREATOR_P_P_H
diff --git a/src/qml/types/qqmlitemmodels.qdoc b/src/qml/types/qqmlitemmodels.qdoc
deleted file mode 100644
index f6e1b0b1b9..0000000000
--- a/src/qml/types/qqmlitemmodels.qdoc
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \page qmodelindex-and-related-classes-in-qml.html
- \title QModelIndex and related Classes in QML
-
- Since Qt 5.5, QModelIndex and QPersistentModelIndex are exposed in QML as
- value-based types. Also exposed in a similar fashion are QModelIndexList,
- QItemSelectionRange and QItemSelection. All objects from these types can
- be passed back and forth between QML and C++ as \c var properties or plain
- JavaScript variables.
-
- Below you will find an overview of the API exposed to QML for these classes.
- For more information, refer to their C++ documentation.
-
- \note Since all these types are exposed as \l{Q_GADGET}{gadgets}, there are no property
- change notification signals emitted. Therefore binding to their properties
- may not give the expected results. This is especially true for QPersistentModelIndex.
-
- \section1 QModelIndex and QPersistentModelIndex Types
-
- \list
- \li \b row : int
- \li \b column : int
- \li \b parent : QModelIndex
- \li \b valid : bool
- \li \b model : QAbstractItemModel
- \li \b internalId : quint64
- \endlist
-
- All these properties are read-only, as are their C++ counterparts.
-
- \note The usual caveats apply to QModelIndex in QML. If the underlying model changes
- or gets deleted, it may become dangerous to access its properties. Therefore, you
- should not store any QModelIndex objects. You can, however, store QPersistentModelIndexe
- objects in a safe way.
-
- \section1 QModelIndexList Type
-
- \l QModelIndexList is exposed in QML as a JavaScript array. Conversions are
- automatically made from and to C++. In fact, any JavaScript array can be
- converted back to QModelIndexList, with non-QModelIndex objects replaced by
- invalid \l{QModelIndex}es.
-
- \note QModelIndex to QPersistentModelIndex conversion happens when accessing
- the array elements because any QModelIndexList property retains reference
- semantics when exposed this way.
-
- \section1 \l QItemSelectionRange Type
-
- \list
- \li \b top : int
- \li \b left : int
- \li \b bottom : int
- \li \b right : int
- \li \b width : int
- \li \b height : int
- \li \b topLeft : QPersistentModelIndex
- \li \b bottomRight : QPersistentModelIndex
- \li \b parent : QModelIndex
- \li \b valid : bool
- \li \b empty : bool
- \li \b model : QAbstractItemModel
- \endlist
-
- All these properties are read-only, as are their C++ counterparts. In addition,
- we also expose the following functions:
-
- \list
- \li bool \b{contains}(QModelIndex \e index)
- \li bool \b{contains}(int \e row, int \e column, QModelIndex \e parentIndex)
- \li bool \b{intersects}(QItemSelectionRange \e other)
- \li QItemSelectionRange \b{intersected}(QItemSelectionRange \e other)
- \endlist
-
- \section1 QItemSelection Type
-
- Similarly to QModelIndexList, \l QItemSelection is exposed in QML as a JavaScript
- array of QItemSelectionRange objects. Conversions are automatically made from and to C++.
- In fact, any JavaScript array can be converted back to QItemSelection, with
- non-QItemSelectionRange objects replaced by empty \l {QItemSelectionRange}s.
-
-
- \sa ItemSelectionModel
-*/
diff --git a/src/qml/types/qqmlitemselectionmodel.qdoc b/src/qml/types/qqmlitemselectionmodel.qdoc
deleted file mode 100644
index 43da4f7a55..0000000000
--- a/src/qml/types/qqmlitemselectionmodel.qdoc
+++ /dev/null
@@ -1,239 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \qmltype ItemSelectionModel
- \instantiates QItemSelectionModel
- \inqmlmodule QtQml.Models
- \since 5.5
- \ingroup qtquick-models
-
- \brief Instantiates a QItemSelectionModel to be used in conjunction
- with a QAbstractItemModel and any view supporting it.
-
- \sa QItemSelectionModel, {Models and Views in Qt Quick}
-*/
-
-
-/*!
- \qmlproperty QAbstractItemModel ItemSelectionModel::model
-
- This property's value must match the view's model.
-*/
-
-/*!
- \qmlproperty bool ItemSelectionModel::hasSelection
- \readonly
-
- It will trigger property binding updates every time \l selectionChanged()
- is emitted, even though its value hasn't changed.
-
- \sa selection, selectedIndexes, select(), selectionChanged()
-*/
-
-/*!
- \qmlproperty QModelIndex ItemSelectionModel::currentIndex
- \readonly
-
- Use \l setCurrentIndex() to set its value.
-
- \sa setCurrentIndex(), currentChanged()
-*/
-
-/*!
- \qmlproperty QModelIndexList ItemSelectionModel::selectedIndexes
- \readonly
-
- Contains the list of all the indexes in the selection model.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isSelected(QModelIndex index)
-
- Returns \c true if the given model item \a index is selected.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isRowSelected(int row, QModelIndex parent)
-
- Returns \c true if all items are selected in the \a row with the given
- \a parent.
-
- Note that this function is usually faster than calling isSelected()
- on all items in the same row, and that unselectable items are ignored.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isColumnSelected(int column, QModelIndex parent)
-
- Returns \c true if all items are selected in the \a column with the given
- \a parent.
-
- Note that this function is usually faster than calling isSelected()
- on all items in the same column, and that unselectable items are ignored.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::rowIntersectsSelection(int row, QModelIndex parent)
-
- Returns \c true if there are any items selected in the \a row with the
- given \a parent.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::columnIntersectsSelection(int column, QModelIndex parent)
-
- Returns \c true if there are any items selected in the \a column with the
- given \a parent.
-*/
-
-/*!
- \qmlmethod QModelIndexList ItemSelectionModel::selectedRows(int column)
-
- Returns the indexes in the given \a column for the rows where all columns
- are selected.
-
- \sa selectedColumns()
-*/
-
-/*!
- \qmlmethod QModelIndexList ItemSelectionModel::selectedColumns(int row)
-
- Returns the indexes in the given \a row for columns where all rows are
- selected.
-
- \sa selectedRows()
-*/
-
-/*!
- \qmlproperty object ItemSelectionModel::selection
- \readonly
-
- Holds the selection ranges stored in the selection model.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::setCurrentIndex(QModelIndex index, SelectionFlags command)
-
- Sets the model item \a index to be the current item, and emits
- currentChanged(). The current item is used for keyboard navigation and
- focus indication; it is independent of any selected items, although a
- selected item can also be the current item.
-
- Depending on the specified \a command, the \a index can also become part
- of the current selection.
-
- Valid \a command values are described in \l {itemselectionmodelselectindex}
- {select(\e index, \e command)}.
-
- \sa select()
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::select(QModelIndex index, SelectionFlags command)
- \keyword itemselectionmodelselectindex
-
- Selects the model item \a index using the specified \a command, and emits
- selectionChanged().
-
- Valid values for the \a command parameter, are:
-
- \value NoUpdate No selection will be made.
- \value Clear The complete selection will be cleared.
- \value Select All specified indexes will be selected.
- \value Deselect All specified indexes will be deselected.
- \value Toggle All specified indexes will be selected or
- deselected depending on their current state.
- \value Current The current selection will be updated.
- \value Rows All indexes will be expanded to span rows.
- \value Columns All indexes will be expanded to span columns.
- \value SelectCurrent A combination of Select and Current, provided for
- convenience.
- \value ToggleCurrent A combination of Toggle and Current, provided for
- convenience.
- \value ClearAndSelect A combination of Clear and Select, provided for
- convenience.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::select(QItemSelection selection, SelectionFlags command)
-
- Selects the item \a selection using the specified \a command, and emits
- selectionChanged().
-
- Valid \a command values are described in \l {itemselectionmodelselectindex}
- {select(\e index, \e command)}.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clear()
-
- Clears the selection model. Emits selectionChanged() and currentChanged().
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::reset()
-
- Clears the selection model. Does not emit any signals.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clearSelection()
-
- Clears the selection in the selection model. Emits selectionChanged().
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clearCurrentIndex()
-
- Clears the current index. Emits currentChanged().
-*/
-
-/*!
- \qmlsignal ItemSelectionModel::selectionChanged(QItemSelection selected, QItemSelection deselected)
-
- This signal is emitted whenever the selection changes. The change in the
- selection is represented as an item selection of \a deselected items and
- an item selection of \a selected items.
-
- Note the that the current index changes independently from the selection.
- Also note that this signal will not be emitted when the item model is reset.
-
- \sa select(), currentChanged()
-*/
-
-/*!
- \qmlsignal ItemSelectionModel::currentChanged(QModelIndex current, QModelIndex previous)
-
- This signal is emitted whenever the current item changes. The \a previous
- model item index is replaced by the \a current index as the selection's
- current item.
-
- Note that this signal will not be emitted when the item model is reset.
-
- \sa currentIndex, setCurrentIndex(), selectionChanged()
-*/
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
deleted file mode 100644
index 5b5bcd8464..0000000000
--- a/src/qml/types/qqmllistmodel.cpp
+++ /dev/null
@@ -1,2900 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistmodel_p_p.h"
-#include "qqmllistmodelworkeragent_p.h"
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmljsengine_p.h>
-#include <private/qjsvalue_p.h>
-
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlnotifier_p.h>
-
-#include <private/qv4object_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4alloca_p.h>
-#include <private/qv4lookup_p.h>
-
-#include <qqmlcontext.h>
-#include <qqmlinfo.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qstack.h>
-#include <QXmlStreamReader>
-#include <QtCore/qdatetime.h>
-#include <QScopedValueRollback>
-
-Q_DECLARE_METATYPE(const QV4::CompiledData::Binding*);
-
-QT_BEGIN_NAMESPACE
-
-// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models.
-enum { MIN_LISTMODEL_UID = 1024 };
-
-static QAtomicInt uidCounter(MIN_LISTMODEL_UID);
-
-template <typename T>
-static bool isMemoryUsed(const char *mem)
-{
- for (size_t i=0 ; i < sizeof(T) ; ++i) {
- if (mem[i] != 0)
- return true;
- }
-
- return false;
-}
-
-static QString roleTypeName(ListLayout::Role::DataType t)
-{
- static const QString roleTypeNames[] = {
- QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"),
- QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"),
- QStringLiteral("DateTime"), QStringLiteral("Function")
- };
-
- if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType)
- return roleTypeNames[t];
-
- return QString();
-}
-
-const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type)
-{
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node) {
- const Role &r = *node->value;
- if (type != r.type)
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
- return r;
- }
-
- return createRole(key, type);
-}
-
-const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::DataType type)
-{
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node) {
- const Role &r = *node->value;
- if (type != r.type)
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
- return r;
- }
-
- QString qkey = key->toQString();
-
- return createRole(qkey, type);
-}
-
-const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
-{
- const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
- const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
-
- Role *r = new Role;
- r->name = key;
- r->type = type;
-
- if (type == Role::List) {
- r->subLayout = new ListLayout;
- } else {
- r->subLayout = nullptr;
- }
-
- int dataSize = dataSizes[type];
- int dataAlignment = dataAlignments[type];
-
- int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1);
- if (dataOffset + dataSize > ListElement::BLOCK_SIZE) {
- r->blockIndex = ++currentBlock;
- r->blockOffset = 0;
- currentBlockOffset = dataSize;
- } else {
- r->blockIndex = currentBlock;
- r->blockOffset = dataOffset;
- currentBlockOffset = dataOffset + dataSize;
- }
-
- int roleIndex = roles.count();
- r->index = roleIndex;
-
- roles.append(r);
- roleHash.insert(key, r);
-
- return *r;
-}
-
-ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0)
-{
- const int otherRolesCount = other->roles.count();
- roles.reserve(otherRolesCount);
- for (int i=0 ; i < otherRolesCount; ++i) {
- Role *role = new Role(other->roles[i]);
- roles.append(role);
- roleHash.insert(role->name, role);
- }
- currentBlockOffset = other->currentBlockOffset;
- currentBlock = other->currentBlock;
-}
-
-ListLayout::~ListLayout()
-{
- qDeleteAll(roles);
-}
-
-void ListLayout::sync(ListLayout *src, ListLayout *target)
-{
- int roleOffset = target->roles.count();
- int newRoleCount = src->roles.count() - roleOffset;
-
- for (int i=0 ; i < newRoleCount ; ++i) {
- Role *role = new Role(src->roles[roleOffset + i]);
- target->roles.append(role);
- target->roleHash.insert(role->name, role);
- }
-
- target->currentBlockOffset = src->currentBlockOffset;
- target->currentBlock = src->currentBlock;
-}
-
-ListLayout::Role::Role(const Role *other)
-{
- name = other->name;
- type = other->type;
- blockIndex = other->blockIndex;
- blockOffset = other->blockOffset;
- index = other->index;
- if (other->subLayout)
- subLayout = new ListLayout(other->subLayout);
- else
- subLayout = nullptr;
-}
-
-ListLayout::Role::~Role()
-{
- delete subLayout;
-}
-
-const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data)
-{
- Role::DataType type;
-
- switch (data.type()) {
- case QVariant::Double: type = Role::Number; break;
- case QVariant::Int: type = Role::Number; break;
- case QVariant::Bool: type = Role::Bool; break;
- case QVariant::String: type = Role::String; break;
- case QVariant::Map: type = Role::VariantMap; break;
- case QVariant::DateTime: type = Role::DateTime; break;
- case QVariant::UserType: {
- if (data.userType() == qMetaTypeId<QJSValue>() &&
- data.value<QJSValue>().isCallable()) {
- type = Role::Function;
- break;
- } else if (data.userType() == qMetaTypeId<const QV4::CompiledData::Binding*>()
- && data.value<const QV4::CompiledData::Binding*>()->isTranslationBinding()) {
- type = Role::String;
- break;
- } else {
- type = Role::List;
- break;
- }
- }
- default: type = Role::Invalid; break;
- }
-
- if (type == Role::Invalid) {
- qmlWarning(nullptr) << "Can't create role for unsupported data type";
- return nullptr;
- }
-
- return &getRoleOrCreate(key, type);
-}
-
-const ListLayout::Role *ListLayout::getExistingRole(const QString &key) const
-{
- Role *r = nullptr;
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node)
- r = node->value;
- return r;
-}
-
-const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) const
-{
- Role *r = nullptr;
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node)
- r = node->value;
- return r;
-}
-
-StringOrTranslation::StringOrTranslation(const QString &s)
-{
- d.setFlag();
- setString(s);
-}
-
-StringOrTranslation::StringOrTranslation(const QV4::CompiledData::Binding *binding)
-{
- d.setFlag();
- clear();
- d = binding;
-}
-
-StringOrTranslation::~StringOrTranslation()
-{
- clear();
-}
-
-void StringOrTranslation::setString(const QString &s)
-{
- d.setFlag();
- clear();
- QStringData *stringData = const_cast<QString &>(s).data_ptr();
- d = stringData;
- if (stringData)
- stringData->ref.ref();
-}
-
-void StringOrTranslation::setTranslation(const QV4::CompiledData::Binding *binding)
-{
- d.setFlag();
- clear();
- d = binding;
-}
-
-QString StringOrTranslation::toString(const QQmlListModel *owner) const
-{
- if (d.isNull())
- return QString();
- if (d.isT1()) {
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
- }
- if (!owner)
- return QString();
- return d.asT2()->valueAsString(owner->m_compilationUnit.data());
-}
-
-QString StringOrTranslation::asString() const
-{
- if (d.isNull())
- return QString();
- if (!d.isT1())
- return QString();
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
-}
-
-void StringOrTranslation::clear()
-{
- if (QStringData *strData = d.isT1() ? d.asT1() : nullptr) {
- if (!strData->ref.deref())
- QStringData::deallocate(strData);
- }
- d = static_cast<QStringData *>(nullptr);
-}
-
-QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementIndex)
-{
- ListElement *e = elements[elementIndex];
- if (e->m_objectCache == nullptr) {
- void *memory = operator new(sizeof(QObject) + sizeof(QQmlData));
- void *ddataMemory = ((char *)memory) + sizeof(QObject);
- e->m_objectCache = new (memory) QObject;
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate::get(e->m_objectCache)->declarativeData = ddata;
- (void)new ModelNodeMetaObject(e->m_objectCache, model, elementIndex);
- }
- return e->m_objectCache;
-}
-
-bool ListModel::sync(ListModel *src, ListModel *target)
-{
- // Sanity check
-
- bool hasChanges = false;
-
- // Build hash of elements <-> uid for each of the lists
- QHash<int, ElementSync> elementHash;
- for (int i = 0; i < target->elements.count(); ++i) {
- ListElement *e = target->elements.at(i);
- int uid = e->getUid();
- ElementSync sync;
- sync.target = e;
- sync.targetIndex = i;
- elementHash.insert(uid, sync);
- }
- for (int i = 0; i < src->elements.count(); ++i) {
- ListElement *e = src->elements.at(i);
- int uid = e->getUid();
-
- QHash<int, ElementSync>::iterator it = elementHash.find(uid);
- if (it == elementHash.end()) {
- ElementSync sync;
- sync.src = e;
- sync.srcIndex = i;
- elementHash.insert(uid, sync);
- } else {
- ElementSync &sync = it.value();
- sync.src = e;
- sync.srcIndex = i;
- }
- }
-
- QQmlListModel *targetModel = target->m_modelCache;
-
- // Get list of elements that are in the target but no longer in the source. These get deleted first.
- int rowsRemoved = 0;
- for (int i = 0 ; i < target->elements.count() ; ++i) {
- ListElement *element = target->elements.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.targetIndex >= 0);
- // need to update the targetIndex, to keep it correct after removals
- s.targetIndex -= rowsRemoved;
- if (s.src == nullptr) {
- Q_ASSERT(s.targetIndex == i);
- hasChanges = true;
- if (targetModel)
- targetModel->beginRemoveRows(QModelIndex(), i, i);
- s.target->destroy(target->m_layout);
- target->elements.removeOne(s.target);
- delete s.target;
- if (targetModel)
- targetModel->endRemoveRows();
- ++rowsRemoved;
- --i;
- continue;
- }
- }
-
- // Sync the layouts
- ListLayout::sync(src->m_layout, target->m_layout);
-
- // Clear the target list, and append in correct order from the source
- target->elements.clear();
- for (int i = 0; i < src->elements.count(); ++i) {
- ListElement *srcElement = src->elements.at(i);
- ElementSync &s = elementHash.find(srcElement->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- ListElement *targetElement = s.target;
- if (targetElement == nullptr) {
- targetElement = new ListElement(srcElement->getUid());
- }
- s.changedRoles = ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout);
- target->elements.append(targetElement);
- }
-
- target->updateCacheIndices();
-
- // Update values stored in target meta objects
- for (int i=0 ; i < target->elements.count() ; ++i) {
- ListElement *e = target->elements[i];
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->updateValues();
- }
-
- // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts,
- // so the model indices can't be out of bounds
- //
- // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
- // model indices are updated correctly
- int rowsInserted = 0;
- for (int i = 0 ; i < target->elements.count() ; ++i) {
- ListElement *element = target->elements.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- s.srcIndex += rowsInserted;
- if (s.srcIndex != s.targetIndex) {
- if (targetModel) {
- if (s.targetIndex == -1) {
- targetModel->beginInsertRows(QModelIndex(), i, i);
- targetModel->endInsertRows();
- } else {
- targetModel->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex);
- targetModel->endMoveRows();
- }
- }
- hasChanges = true;
- ++rowsInserted;
- }
- if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) {
- QModelIndex idx = targetModel->createIndex(i, 0);
- if (targetModel)
- targetModel->dataChanged(idx, idx, s.changedRoles);
- hasChanges = true;
- }
- }
- return hasChanges;
-}
-
-ListModel::ListModel(ListLayout *layout, QQmlListModel *modelCache) : m_layout(layout), m_modelCache(modelCache)
-{
-}
-
-void ListModel::destroy()
-{
- for (const auto &destroyer : remove(0, elements.count()))
- destroyer();
-
- m_layout = nullptr;
- if (m_modelCache && m_modelCache->m_primary == false)
- delete m_modelCache;
- m_modelCache = nullptr;
-}
-
-int ListModel::appendElement()
-{
- int elementIndex = elements.count();
- newElement(elementIndex);
- return elementIndex;
-}
-
-void ListModel::insertElement(int index)
-{
- newElement(index);
- updateCacheIndices(index);
-}
-
-void ListModel::move(int from, int to, int n)
-{
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- from = tto;
- to = tto+n;
- n = tfrom-tto;
- }
-
- QPODVector<ListElement *, 4> store;
- for (int i=0 ; i < (to-from) ; ++i)
- store.append(elements[from+n+i]);
- for (int i=0 ; i < n ; ++i)
- store.append(elements[from+i]);
- for (int i=0 ; i < store.count() ; ++i)
- elements[from+i] = store[i];
-
- updateCacheIndices(from, to + n);
-}
-
-void ListModel::newElement(int index)
-{
- ListElement *e = new ListElement;
- elements.insert(index, e);
-}
-
-void ListModel::updateCacheIndices(int start, int end)
-{
- int count = elements.count();
-
- if (end < 0 || end > count)
- end = count;
-
- for (int i = start; i < end; ++i) {
- ListElement *e = elements.at(i);
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->m_elementIndex = i;
- }
-}
-
-QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng)
-{
- if (roleIndex >= m_layout->roleCount())
- return QVariant();
- ListElement *e = elements[elementIndex];
- const ListLayout::Role &r = m_layout->getExistingRole(roleIndex);
- return e->getProperty(r, owner, eng);
-}
-
-ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role)
-{
- ListElement *e = elements[elementIndex];
- return e->getListProperty(role);
-}
-
-void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
-{
- ListElement *e = elements[elementIndex];
-
- QV4::ExecutionEngine *v4 = object->engine();
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope);
-
- QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedString propertyName(scope);
- QV4::ScopedValue propertyValue(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(propertyValue);
- if (!propertyName)
- break;
-
- // Check if this key exists yet
- int roleIndex = -1;
-
- // Add the value now
- if (const QV4::String *s = propertyValue->as<QV4::String>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
- roleIndex = e->setStringProperty(r, s->toQString());
- } else if (propertyValue->isNumber()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
- roleIndex = e->setDoubleProperty(r, propertyValue->asDouble());
- } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- roleIndex = e->setListProperty(r, subModel);
- } else if (propertyValue->isBoolean()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
- roleIndex = e->setBoolProperty(r, propertyValue->booleanValue());
- } else if (QV4::DateObject *dd = propertyValue->as<QV4::DateObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
- QDateTime dt = dd->toQDateTime();
- roleIndex = e->setDateTimeProperty(r, dt);
- } else if (QV4::FunctionObject *f = propertyValue->as<QV4::FunctionObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Function);
- QV4::ScopedFunctionObject func(scope, f);
- QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, v4, func);
- roleIndex = e->setFunctionProperty(r, jsv);
- } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
- if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
- if (role.type == ListLayout::Role::QObject)
- roleIndex = e->setQObjectProperty(role, o);
- } else {
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap) {
- QV4::ScopedObject obj(scope, o);
- roleIndex = e->setVariantMapProperty(role, obj);
- }
- }
- } else if (propertyValue->isNullOrUndefined()) {
- const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
- if (r)
- e->clearProperty(*r);
- }
-
- if (roleIndex != -1)
- roles->append(roleIndex);
- }
-
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->updateValues(*roles);
-}
-
-void ListModel::set(int elementIndex, QV4::Object *object)
-{
- if (!object)
- return;
-
- ListElement *e = elements[elementIndex];
-
- QV4::ExecutionEngine *v4 = object->engine();
- QV4::Scope scope(v4);
-
- QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedString propertyName(scope);
- QV4::ScopedValue propertyValue(scope);
- QV4::ScopedObject o(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(propertyValue);
- if (!propertyName)
- break;
-
- // Add the value now
- if (QV4::String *s = propertyValue->stringValue()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
- if (r.type == ListLayout::Role::String)
- e->setStringPropertyFast(r, s->toQString());
- } else if (propertyValue->isNumber()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
- if (r.type == ListLayout::Role::Number) {
- e->setDoublePropertyFast(r, propertyValue->asDouble());
- }
- } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- if (r.type == ListLayout::Role::List) {
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- e->setListPropertyFast(r, subModel);
- }
- } else if (propertyValue->isBoolean()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
- if (r.type == ListLayout::Role::Bool) {
- e->setBoolPropertyFast(r, propertyValue->booleanValue());
- }
- } else if (QV4::DateObject *date = propertyValue->as<QV4::DateObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
- if (r.type == ListLayout::Role::DateTime) {
- QDateTime dt = date->toQDateTime();;
- e->setDateTimePropertyFast(r, dt);
- }
- } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
- if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
- if (r.type == ListLayout::Role::QObject)
- e->setQObjectPropertyFast(r, o);
- } else {
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap)
- e->setVariantMapFast(role, o);
- }
- } else if (propertyValue->isNullOrUndefined()) {
- const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
- if (r)
- e->clearProperty(*r);
- }
- }
-}
-
-QVector<std::function<void()>> ListModel::remove(int index, int count)
-{
- QVector<std::function<void()>> toDestroy;
- auto layout = m_layout;
- for (int i=0 ; i < count ; ++i) {
- auto element = elements[index+i];
- toDestroy.append([element, layout](){
- element->destroy(layout);
- delete element;
- });
- }
- elements.remove(index, count);
- updateCacheIndices(index);
- return toDestroy;
-}
-
-void ListModel::insert(int elementIndex, QV4::Object *object)
-{
- insertElement(elementIndex);
- set(elementIndex, object);
-}
-
-int ListModel::append(QV4::Object *object)
-{
- int elementIndex = appendElement();
- set(elementIndex, object);
- return elementIndex;
-}
-
-int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data)
-{
- int roleIndex = -1;
-
- if (elementIndex >= 0 && elementIndex < elements.count()) {
- ListElement *e = elements[elementIndex];
-
- const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data);
- if (r) {
- roleIndex = e->setVariantProperty(*r, data);
-
- ModelNodeMetaObject *cache = e->objectCache();
-
- if (roleIndex != -1 && cache)
- cache->updateValues(QVector<int>(1, roleIndex));
- }
- }
-
- return roleIndex;
-}
-
-int ListModel::setExistingProperty(int elementIndex, const QString &key, const QV4::Value &data, QV4::ExecutionEngine *eng)
-{
- int roleIndex = -1;
-
- if (elementIndex >= 0 && elementIndex < elements.count()) {
- ListElement *e = elements[elementIndex];
- const ListLayout::Role *r = m_layout->getExistingRole(key);
- if (r)
- roleIndex = e->setJsProperty(*r, data, eng);
- }
-
- return roleIndex;
-}
-
-inline char *ListElement::getPropertyMemory(const ListLayout::Role &role)
-{
- ListElement *e = this;
- int blockIndex = 0;
- while (blockIndex < role.blockIndex) {
- if (e->next == nullptr) {
- e->next = new ListElement;
- e->next->uid = uid;
- }
- e = e->next;
- ++blockIndex;
- }
-
- char *mem = &e->data[role.blockOffset];
- return mem;
-}
-
-ModelNodeMetaObject *ListElement::objectCache()
-{
- if (!m_objectCache)
- return nullptr;
- return ModelNodeMetaObject::get(m_objectCache);
-}
-
-StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem);
- return s;
-}
-
-QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- QPointer<QObject> *o = reinterpret_cast<QPointer<QObject> *>(mem);
- return o->data();
-}
-
-QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
-{
- QVariantMap *map = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem))
- map = reinterpret_cast<QVariantMap *>(mem);
-
- return map;
-}
-
-QDateTime *ListElement::getDateTimeProperty(const ListLayout::Role &role)
-{
- QDateTime *dt = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QDateTime>(mem))
- dt = reinterpret_cast<QDateTime *>(mem);
-
- return dt;
-}
-
-QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
-{
- QJSValue *f = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QJSValue>(mem))
- f = reinterpret_cast<QJSValue *>(mem);
-
- return f;
-}
-
-QPointer<QObject> *ListElement::getGuardProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
-
- bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
-
- QPointer<QObject> *o = nullptr;
-
- if (existingGuard)
- o = reinterpret_cast<QPointer<QObject> *>(mem);
-
- return o;
-}
-
-ListModel *ListElement::getListProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- return *value;
-}
-
-QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng)
-{
- char *mem = getPropertyMemory(role);
-
- QVariant data;
-
- switch (role.type) {
- case ListLayout::Role::Number:
- {
- double *value = reinterpret_cast<double *>(mem);
- data = *value;
- }
- break;
- case ListLayout::Role::String:
- {
- StringOrTranslation *value = reinterpret_cast<StringOrTranslation *>(mem);
- if (value->isSet())
- data = value->toString(owner);
- }
- break;
- case ListLayout::Role::Bool:
- {
- bool *value = reinterpret_cast<bool *>(mem);
- data = *value;
- }
- break;
- case ListLayout::Role::List:
- {
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- ListModel *model = *value;
-
- if (model) {
- if (model->m_modelCache == nullptr) {
- model->m_modelCache = new QQmlListModel(owner, model, eng);
- QQmlEngine::setContextForObject(model->m_modelCache, QQmlEngine::contextForObject(owner));
- }
-
- QObject *object = model->m_modelCache;
- data = QVariant::fromValue(object);
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QPointer<QObject> *guard = reinterpret_cast<QPointer<QObject> *>(mem);
- QObject *object = guard->data();
- if (object)
- data = QVariant::fromValue(object);
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- data = *map;
- }
- }
- break;
- case ListLayout::Role::DateTime:
- {
- if (isMemoryUsed<QDateTime>(mem)) {
- QDateTime *dt = reinterpret_cast<QDateTime *>(mem);
- data = *dt;
- }
- }
- break;
- case ListLayout::Role::Function:
- {
- if (isMemoryUsed<QJSValue>(mem)) {
- QJSValue *func = reinterpret_cast<QJSValue *>(mem);
- data = QVariant::fromValue(*func);
- }
- }
- break;
- default:
- break;
- }
-
- return data;
-}
-
-int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::String) {
- char *mem = getPropertyMemory(role);
- StringOrTranslation *c = reinterpret_cast<StringOrTranslation *>(mem);
- bool changed;
- if (!c->isSet() || c->isTranslation())
- changed = true;
- else
- changed = c->asString().compare(s) != 0;
- c->setString(s);
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setDoubleProperty(const ListLayout::Role &role, double d)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Number) {
- char *mem = getPropertyMemory(role);
- double *value = reinterpret_cast<double *>(mem);
- bool changed = *value != d;
- *value = d;
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setBoolProperty(const ListLayout::Role &role, bool b)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Bool) {
- char *mem = getPropertyMemory(role);
- bool *value = reinterpret_cast<bool *>(mem);
- bool changed = *value != b;
- *value = b;
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::List) {
- char *mem = getPropertyMemory(role);
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- if (*value && *value != m) {
- (*value)->destroy();
- delete *value;
- }
- *value = m;
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::QObject) {
- char *mem = getPropertyMemory(role);
- QPointer<QObject> *g = reinterpret_cast<QPointer<QObject> *>(mem);
- bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
- bool changed;
- if (existingGuard) {
- changed = g->data() != o;
- g->~QPointer();
- } else {
- changed = true;
- }
- new (mem) QPointer<QObject>(o);
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::VariantMap) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- map->~QMap();
- }
- new (mem) QVariantMap(o->engine()->variantMapFromJS(o));
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::VariantMap) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- if (m && map->isSharedWith(*m))
- return roleIndex;
- map->~QMap();
- } else if (!m) {
- return roleIndex;
- }
- if (m)
- new (mem) QVariantMap(*m);
- else
- new (mem) QVariantMap;
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::DateTime) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QDateTime>(mem)) {
- QDateTime *dt = reinterpret_cast<QDateTime *>(mem);
- dt->~QDateTime();
- }
- new (mem) QDateTime(dt);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValue &f)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Function) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QJSValue>(mem)) {
- QJSValue *f = reinterpret_cast<QJSValue *>(mem);
- f->~QJSValue();
- }
- new (mem) QJSValue(f);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::String) {
- char *mem = getPropertyMemory(role);
- StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem);
- s->setTranslation(b);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-
-void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s)
-{
- char *mem = getPropertyMemory(role);
- new (mem) StringOrTranslation(s);
-}
-
-void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d)
-{
- char *mem = getPropertyMemory(role);
- double *value = new (mem) double;
- *value = d;
-}
-
-void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
-{
- char *mem = getPropertyMemory(role);
- bool *value = new (mem) bool;
- *value = b;
-}
-
-void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QPointer<QObject>(o);
-}
-
-void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
-{
- char *mem = getPropertyMemory(role);
- ListModel **value = new (mem) ListModel *;
- *value = m;
-}
-
-void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::Object *o)
-{
- char *mem = getPropertyMemory(role);
- QVariantMap *map = new (mem) QVariantMap;
- *map = o->engine()->variantMapFromJS(o);
-}
-
-void ListElement::setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QDateTime(dt);
-}
-
-void ListElement::setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QJSValue(f);
-}
-
-void ListElement::clearProperty(const ListLayout::Role &role)
-{
- switch (role.type) {
- case ListLayout::Role::String:
- setStringProperty(role, QString());
- break;
- case ListLayout::Role::Number:
- setDoubleProperty(role, 0.0);
- break;
- case ListLayout::Role::Bool:
- setBoolProperty(role, false);
- break;
- case ListLayout::Role::List:
- setListProperty(role, nullptr);
- break;
- case ListLayout::Role::QObject:
- setQObjectProperty(role, nullptr);
- break;
- case ListLayout::Role::DateTime:
- setDateTimeProperty(role, QDateTime());
- break;
- case ListLayout::Role::VariantMap:
- setVariantMapProperty(role, (QVariantMap *)nullptr);
- break;
- case ListLayout::Role::Function:
- setFunctionProperty(role, QJSValue());
- break;
- default:
- break;
- }
-}
-
-ListElement::ListElement()
-{
- m_objectCache = nullptr;
- uid = uidCounter.fetchAndAddOrdered(1);
- next = nullptr;
- memset(data, 0, sizeof(data));
-}
-
-ListElement::ListElement(int existingUid)
-{
- m_objectCache = nullptr;
- uid = existingUid;
- next = nullptr;
- memset(data, 0, sizeof(data));
-}
-
-ListElement::~ListElement()
-{
- delete next;
-}
-
-QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout)
-{
- QVector<int> changedRoles;
- for (int i=0 ; i < srcLayout->roleCount() ; ++i) {
- const ListLayout::Role &srcRole = srcLayout->getExistingRole(i);
- const ListLayout::Role &targetRole = targetLayout->getExistingRole(i);
-
- int roleIndex = -1;
- switch (srcRole.type) {
- case ListLayout::Role::List:
- {
- ListModel *srcSubModel = src->getListProperty(srcRole);
- ListModel *targetSubModel = target->getListProperty(targetRole);
-
- if (srcSubModel) {
- if (targetSubModel == nullptr) {
- targetSubModel = new ListModel(targetRole.subLayout, nullptr);
- target->setListPropertyFast(targetRole, targetSubModel);
- }
- if (ListModel::sync(srcSubModel, targetSubModel))
- roleIndex = targetRole.index;
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QObject *object = src->getQObjectProperty(srcRole);
- roleIndex = target->setQObjectProperty(targetRole, object);
- }
- break;
- case ListLayout::Role::String:
- case ListLayout::Role::Number:
- case ListLayout::Role::Bool:
- case ListLayout::Role::DateTime:
- case ListLayout::Role::Function:
- {
- QVariant v = src->getProperty(srcRole, nullptr, nullptr);
- roleIndex = target->setVariantProperty(targetRole, v);
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- QVariantMap *map = src->getVariantMapProperty(srcRole);
- roleIndex = target->setVariantMapProperty(targetRole, map);
- }
- break;
- default:
- break;
- }
- if (roleIndex >= 0)
- changedRoles << roleIndex;
- }
-
- return changedRoles;
-}
-
-void ListElement::destroy(ListLayout *layout)
-{
- if (layout) {
- for (int i=0 ; i < layout->roleCount() ; ++i) {
- const ListLayout::Role &r = layout->getExistingRole(i);
-
- switch (r.type) {
- case ListLayout::Role::String:
- {
- StringOrTranslation *string = getStringProperty(r);
- if (string)
- string->~StringOrTranslation();
- }
- break;
- case ListLayout::Role::List:
- {
- ListModel *model = getListProperty(r);
- if (model) {
- model->destroy();
- delete model;
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QPointer<QObject> *guard = getGuardProperty(r);
- if (guard)
- guard->~QPointer();
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- QVariantMap *map = getVariantMapProperty(r);
- if (map)
- map->~QMap();
- }
- break;
- case ListLayout::Role::DateTime:
- {
- QDateTime *dt = getDateTimeProperty(r);
- if (dt)
- dt->~QDateTime();
- }
- break;
- case ListLayout::Role::Function:
- {
- QJSValue *f = getFunctionProperty(r);
- if (f)
- f->~QJSValue();
- }
- break;
- default:
- // other types don't need explicit cleanup.
- break;
- }
- }
-
- if (m_objectCache) {
- m_objectCache->~QObject();
- operator delete(m_objectCache);
- }
- }
-
- if (next)
- next->destroy(nullptr);
- uid = -1;
-}
-
-int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d)
-{
- int roleIndex = -1;
-
- switch (role.type) {
- case ListLayout::Role::Number:
- roleIndex = setDoubleProperty(role, d.toDouble());
- break;
- case ListLayout::Role::String:
- if (d.userType() == qMetaTypeId<const QV4::CompiledData::Binding *>())
- roleIndex = setTranslationProperty(role, d.value<const QV4::CompiledData::Binding*>());
- else
- roleIndex = setStringProperty(role, d.toString());
- break;
- case ListLayout::Role::Bool:
- roleIndex = setBoolProperty(role, d.toBool());
- break;
- case ListLayout::Role::List:
- roleIndex = setListProperty(role, d.value<ListModel *>());
- break;
- case ListLayout::Role::VariantMap: {
- QVariantMap map = d.toMap();
- roleIndex = setVariantMapProperty(role, &map);
- }
- break;
- case ListLayout::Role::DateTime:
- roleIndex = setDateTimeProperty(role, d.toDateTime());
- break;
- case ListLayout::Role::Function:
- roleIndex = setFunctionProperty(role, d.value<QJSValue>());
- break;
- default:
- break;
- }
-
- return roleIndex;
-}
-
-int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d, QV4::ExecutionEngine *eng)
-{
- // Check if this key exists yet
- int roleIndex = -1;
-
- QV4::Scope scope(eng);
-
- // Add the value now
- if (d.isString()) {
- QString qstr = d.toQString();
- roleIndex = setStringProperty(role, qstr);
- } else if (d.isNumber()) {
- roleIndex = setDoubleProperty(role, d.asDouble());
- } else if (d.as<QV4::ArrayObject>()) {
- QV4::ScopedArrayObject a(scope, d);
- if (role.type == ListLayout::Role::List) {
- QV4::Scope scope(a->engine());
- QV4::ScopedObject o(scope);
-
- ListModel *subModel = new ListModel(role.subLayout, nullptr);
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
- roleIndex = setListProperty(role, subModel);
- } else {
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List));
- }
- } else if (d.isBoolean()) {
- roleIndex = setBoolProperty(role, d.booleanValue());
- } else if (d.as<QV4::DateObject>()) {
- QV4::Scoped<QV4::DateObject> dd(scope, d);
- QDateTime dt = dd->toQDateTime();
- roleIndex = setDateTimeProperty(role, dt);
- } else if (d.as<QV4::FunctionObject>()) {
- QV4::ScopedFunctionObject f(scope, d);
- QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, eng, f);
- roleIndex = setFunctionProperty(role, jsv);
- } else if (d.isObject()) {
- QV4::ScopedObject o(scope, d);
- QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>();
- if (role.type == ListLayout::Role::QObject && wrapper) {
- QObject *o = wrapper->object();
- roleIndex = setQObjectProperty(role, o);
- } else if (role.type == ListLayout::Role::VariantMap) {
- roleIndex = setVariantMapProperty(role, o);
- }
- } else if (d.isNullOrUndefined()) {
- clearProperty(role);
- }
-
- return roleIndex;
-}
-
-ModelNodeMetaObject::ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex)
-: QQmlOpenMetaObject(object), m_enabled(false), m_model(model), m_elementIndex(elementIndex), m_initialized(false)
-{}
-
-void ModelNodeMetaObject::initialize()
-{
- const int roleCount = m_model->m_listModel->roleCount();
- QVector<QByteArray> properties;
- properties.reserve(roleCount);
- for (int i = 0 ; i < roleCount ; ++i) {
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i);
- QByteArray name = role.name.toUtf8();
- properties << name;
- }
- type()->createProperties(properties);
- updateValues();
- m_enabled = true;
-}
-
-ModelNodeMetaObject::~ModelNodeMetaObject()
-{
-}
-
-QAbstractDynamicMetaObject *ModelNodeMetaObject::toDynamicMetaObject(QObject *object)
-{
- if (!m_initialized) {
- m_initialized = true;
- initialize();
- }
- return QQmlOpenMetaObject::toDynamicMetaObject(object);
-}
-
-ModelNodeMetaObject *ModelNodeMetaObject::get(QObject *obj)
-{
- QObjectPrivate *op = QObjectPrivate::get(obj);
- return static_cast<ModelNodeMetaObject*>(op->metaObject);
-}
-
-void ModelNodeMetaObject::updateValues()
-{
- const int roleCount = m_model->m_listModel->roleCount();
- if (!m_initialized) {
- if (roleCount) {
- Q_ALLOCA_VAR(int, changedRoles, roleCount * sizeof(int));
- for (int i = 0; i < roleCount; ++i)
- changedRoles[i] = i;
- emitDirectNotifies(changedRoles, roleCount);
- }
- return;
- }
- for (int i=0 ; i < roleCount ; ++i) {
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i);
- QByteArray name = role.name.toUtf8();
- const QVariant &data = m_model->data(m_elementIndex, i);
- setValue(name, data, role.type == ListLayout::Role::List);
- }
-}
-
-void ModelNodeMetaObject::updateValues(const QVector<int> &roles)
-{
- if (!m_initialized) {
- emitDirectNotifies(roles.constData(), roles.count());
- return;
- }
- int roleCount = roles.count();
- for (int i=0 ; i < roleCount ; ++i) {
- int roleIndex = roles.at(i);
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex);
- QByteArray name = role.name.toUtf8();
- const QVariant &data = m_model->data(m_elementIndex, roleIndex);
- setValue(name, data, role.type == ListLayout::Role::List);
- }
-}
-
-void ModelNodeMetaObject::propertyWritten(int index)
-{
- if (!m_enabled)
- return;
-
- QString propName = QString::fromUtf8(name(index));
- const QVariant value = this->value(index);
-
- QV4::Scope scope(m_model->engine());
- QV4::ScopedValue v(scope, scope.engine->fromVariant(value));
-
- int roleIndex = m_model->m_listModel->setExistingProperty(m_elementIndex, propName, v, scope.engine);
- if (roleIndex != -1)
- m_model->emitItemsChanged(m_elementIndex, 1, QVector<int>(1, roleIndex));
-}
-
-// Does the emission of the notifiers when we haven't created the meta-object yet
-void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCount)
-{
- Q_ASSERT(!m_initialized);
- QQmlData *ddata = QQmlData::get(object(), /*create*/false);
- if (!ddata)
- return;
- // There's nothing to emit if we're a list model in a worker thread.
- if (!qmlEngine(m_model))
- return;
- for (int i = 0; i < roleCount; ++i) {
- const int changedRole = changedRoles[i];
- QQmlNotifier::notify(ddata, changedRole);
- }
-}
-
-namespace QV4 {
-
-bool ModelObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
-{
- if (!id.isString())
- return Object::virtualPut(m, id, value, receiver);
- QString propName = id.toQString();
-
- ModelObject *that = static_cast<ModelObject*>(m);
-
- ExecutionEngine *eng = that->engine();
- const int elementIndex = that->d()->elementIndex();
- int roleIndex = that->d()->m_model->m_listModel->setExistingProperty(elementIndex, propName, value, eng);
- if (roleIndex != -1)
- that->d()->m_model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
-
- ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
- if (mo->initialized())
- mo->emitPropertyNotification(propName.toUtf8());
- return true;
-}
-
-ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
-{
- if (!id.isString())
- return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
-
- const ModelObject *that = static_cast<const ModelObject*>(m);
- Scope scope(that);
- ScopedString name(scope, id.asStringOrSymbol());
- const ListLayout::Role *role = that->d()->m_model->m_listModel->getExistingRole(name);
- if (!role)
- return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
- if (hasProperty)
- *hasProperty = true;
-
- if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
- if (ep && ep->propertyCapture)
- ep->propertyCapture->captureProperty(that->object(), -1, role->index, /*doNotify=*/ false);
- }
-
- const int elementIndex = that->d()->elementIndex();
- QVariant value = that->d()->m_model->data(elementIndex, role->index);
- return that->engine()->fromVariant(value);
-}
-
-ReturnedValue ModelObject::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
-{
- lookup->getter = Lookup::getterFallback;
- return lookup->getter(lookup, engine, *object);
-}
-
-struct ModelObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
-{
- int roleNameIndex = 0;
- ~ModelObjectOwnPropertyKeyIterator() override = default;
- PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
-
-};
-
-PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
-{
- const ModelObject *that = static_cast<const ModelObject *>(o);
-
- ExecutionEngine *v4 = that->engine();
- if (roleNameIndex < that->listModel()->roleCount()) {
- Scope scope(that->engine());
- const ListLayout::Role &role = that->listModel()->getExistingRole(roleNameIndex);
- ++roleNameIndex;
- ScopedString roleName(scope, v4->newString(role.name));
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd) {
- QVariant value = that->d()->m_model->data(that->d()->elementIndex(), role.index);
- pd->value = v4->fromVariant(value);
- }
- return roleName->toPropertyKey();
- }
-
- // Fall back to QV4::Object as opposed to QV4::QObjectWrapper otherwise it will add
- // unnecessary entries that relate to the roles used. These just create extra work
- // later on as they will just be ignored.
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
-}
-
-OwnPropertyKeyIterator *ModelObject::virtualOwnPropertyKeys(const Object *m, Value *target)
-{
- *target = *m;
- return new ModelObjectOwnPropertyKeyIterator;
-}
-
-DEFINE_OBJECT_VTABLE(ModelObject);
-
-} // namespace QV4
-
-DynamicRoleModelNode::DynamicRoleModelNode(QQmlListModel *owner, int uid) : m_owner(owner), m_uid(uid), m_meta(new DynamicRoleModelNodeMetaObject(this))
-{
- setNodeUpdatesEnabled(true);
-}
-
-DynamicRoleModelNode *DynamicRoleModelNode::create(const QVariantMap &obj, QQmlListModel *owner)
-{
- DynamicRoleModelNode *object = new DynamicRoleModelNode(owner, uidCounter.fetchAndAddOrdered(1));
- QVector<int> roles;
- object->updateValues(obj, roles);
- return object;
-}
-
-QVector<int> DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target)
-{
- QVector<int> changedRoles;
- for (int i = 0; i < src->m_meta->count(); ++i) {
- const QByteArray &name = src->m_meta->name(i);
- QVariant value = src->m_meta->value(i);
-
- QQmlListModel *srcModel = qobject_cast<QQmlListModel *>(value.value<QObject *>());
- QQmlListModel *targetModel = qobject_cast<QQmlListModel *>(target->m_meta->value(i).value<QObject *>());
-
- bool modelHasChanges = false;
- if (srcModel) {
- if (targetModel == nullptr)
- targetModel = QQmlListModel::createWithOwner(target->m_owner);
-
- modelHasChanges = QQmlListModel::sync(srcModel, targetModel);
-
- QObject *targetModelObject = targetModel;
- value = QVariant::fromValue(targetModelObject);
- } else if (targetModel) {
- delete targetModel;
- }
-
- if (target->setValue(name, value) || modelHasChanges)
- changedRoles << target->m_owner->m_roles.indexOf(QString::fromUtf8(name));
- }
- return changedRoles;
-}
-
-void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int> &roles)
-{
- for (auto it = object.cbegin(), end = object.cend(); it != end; ++it) {
- const QString &key = it.key();
-
- int roleIndex = m_owner->m_roles.indexOf(key);
- if (roleIndex == -1) {
- roleIndex = m_owner->m_roles.count();
- m_owner->m_roles.append(key);
- }
-
- QVariant value = it.value();
-
- // A JS array/object is translated into a (hierarchical) QQmlListModel,
- // so translate to a variant map/list first with toVariant().
- if (value.userType() == qMetaTypeId<QJSValue>())
- value = value.value<QJSValue>().toVariant();
-
- if (value.type() == QVariant::List) {
- QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner);
-
- QVariantList subArray = value.toList();
- QVariantList::const_iterator subIt = subArray.cbegin();
- QVariantList::const_iterator subEnd = subArray.cend();
- while (subIt != subEnd) {
- const QVariantMap &subObject = subIt->toMap();
- subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
- ++subIt;
- }
-
- QObject *subModelObject = subModel;
- value = QVariant::fromValue(subModelObject);
- }
-
- const QByteArray &keyUtf8 = key.toUtf8();
-
- QQmlListModel *existingModel = qobject_cast<QQmlListModel *>(m_meta->value(keyUtf8).value<QObject *>());
- delete existingModel;
-
- if (m_meta->setValue(keyUtf8, value))
- roles << roleIndex;
- }
-}
-
-DynamicRoleModelNodeMetaObject::DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object)
- : QQmlOpenMetaObject(object), m_enabled(false), m_owner(object)
-{
-}
-
-DynamicRoleModelNodeMetaObject::~DynamicRoleModelNodeMetaObject()
-{
- for (int i=0 ; i < count() ; ++i) {
- QQmlListModel *subModel = qobject_cast<QQmlListModel *>(value(i).value<QObject *>());
- delete subModel;
- }
-}
-
-void DynamicRoleModelNodeMetaObject::propertyWrite(int index)
-{
- if (!m_enabled)
- return;
-
- QVariant v = value(index);
- QQmlListModel *model = qobject_cast<QQmlListModel *>(v.value<QObject *>());
- delete model;
-}
-
-void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
-{
- if (!m_enabled)
- return;
-
- QQmlListModel *parentModel = m_owner->m_owner;
-
- QVariant v = value(index);
-
- // A JS array/object is translated into a (hierarchical) QQmlListModel,
- // so translate to a variant map/list first with toVariant().
- if (v.userType() == qMetaTypeId<QJSValue>())
- v= v.value<QJSValue>().toVariant();
-
- if (v.type() == QVariant::List) {
- QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel);
-
- QVariantList subArray = v.toList();
- QVariantList::const_iterator subIt = subArray.cbegin();
- QVariantList::const_iterator subEnd = subArray.cend();
- while (subIt != subEnd) {
- const QVariantMap &subObject = subIt->toMap();
- subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
- ++subIt;
- }
-
- QObject *subModelObject = subModel;
- v = QVariant::fromValue(subModelObject);
-
- setValue(index, v);
- }
-
- int elementIndex = parentModel->m_modelObjects.indexOf(m_owner);
- if (elementIndex != -1) {
- int roleIndex = parentModel->m_roles.indexOf(QString::fromLatin1(name(index).constData()));
- if (roleIndex != -1)
- parentModel->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
- }
-}
-
-/*!
- \qmltype ListModel
- \instantiates QQmlListModel
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Defines a free-form list data source.
-
- The ListModel is a simple container of ListElement definitions, each
- containing data roles. The contents can be defined dynamically, or
- explicitly in QML.
-
- The number of elements in the model can be obtained from its \l count property.
- A number of familiar methods are also provided to manipulate the contents of the
- model, including append(), insert(), move(), remove() and set(). These methods
- accept dictionaries as their arguments; these are translated to ListElement objects
- by the model.
-
- Elements can be manipulated via the model using the setProperty() method, which
- allows the roles of the specified element to be set and changed.
-
- \section1 Example Usage
-
- The following example shows a ListModel containing three elements, with the roles
- "name" and "cost".
-
- \div {class="float-right"}
- \inlineimage listmodel.png
- \enddiv
-
- \snippet qml/listmodel/listmodel.qml 0
-
- Roles (properties) in each element must begin with a lower-case letter and
- should be common to all elements in a model. The ListElement documentation
- provides more guidelines for how elements should be defined.
-
- Since the example model contains an \c id property, it can be referenced
- by views, such as the ListView in this example:
-
- \snippet qml/listmodel/listmodel-simple.qml 0
- \dots 8
- \snippet qml/listmodel/listmodel-simple.qml 1
-
- It is possible for roles to contain list data. In the following example we
- create a list of fruit attributes:
-
- \snippet qml/listmodel/listmodel-nested.qml model
-
- The delegate displays all the fruit attributes:
-
- \div {class="float-right"}
- \inlineimage listmodel-nested.png
- \enddiv
-
- \snippet qml/listmodel/listmodel-nested.qml delegate
-
- \section1 Modifying List Models
-
- The content of a ListModel may be created and modified using the clear(),
- append(), set(), insert() and setProperty() methods. For example:
-
- \snippet qml/listmodel/listmodel-modify.qml delegate
-
- Note that when creating content dynamically the set of available properties
- cannot be changed once set. Whatever properties are first added to the model
- are the only permitted properties in the model.
-
- \section1 Using Threaded List Models with WorkerScript
-
- ListModel can be used together with WorkerScript access a list model
- from multiple threads. This is useful if list modifications are
- synchronous and take some time: the list operations can be moved to a
- different thread to avoid blocking of the main GUI thread.
-
- Here is an example that uses WorkerScript to periodically append the
- current time to a list model:
-
- \snippet ../quick/threading/threadedlistmodel/timedisplay.qml 0
-
- The included file, \tt dataloader.mjs, looks like this:
-
- \snippet ../quick/threading/threadedlistmodel/dataloader.mjs 0
-
- The timer in the main example sends messages to the worker script by calling
- \l WorkerScript::sendMessage(). When this message is received,
- \c WorkerScript.onMessage() is invoked in \c dataloader.mjs,
- which appends the current time to the list model.
-
- Note the call to sync() from the external thread.
- You must call sync() or else the changes made to the list from that
- thread will not be reflected in the list model in the main thread.
-
- \sa {qml-data-models}{Data Models}, {Qt Quick Examples - Threading}, {Qt QML}
-*/
-
-QQmlListModel::QQmlListModel(QObject *parent)
-: QAbstractListModel(parent)
-{
- m_mainThread = true;
- m_primary = true;
- m_agent = nullptr;
- m_dynamicRoles = false;
-
- m_layout = new ListLayout;
- m_listModel = new ListModel(m_layout, this);
-
- m_engine = nullptr;
-}
-
-QQmlListModel::QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::ExecutionEngine *engine, QObject *parent)
-: QAbstractListModel(parent)
-{
- m_mainThread = owner->m_mainThread;
- m_primary = false;
- m_agent = owner->m_agent;
-
- Q_ASSERT(owner->m_dynamicRoles == false);
- m_dynamicRoles = false;
- m_layout = nullptr;
- m_listModel = data;
-
- m_engine = engine;
- m_compilationUnit = owner->m_compilationUnit;
-}
-
-QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent)
-: QAbstractListModel(agent)
-{
- m_mainThread = false;
- m_primary = true;
- m_agent = agent;
- m_dynamicRoles = orig->m_dynamicRoles;
-
- m_layout = new ListLayout(orig->m_layout);
- m_listModel = new ListModel(m_layout, this);
-
- if (m_dynamicRoles)
- sync(orig, this);
- else
- ListModel::sync(orig->m_listModel, m_listModel);
-
- m_engine = nullptr;
- m_compilationUnit = orig->m_compilationUnit;
-}
-
-QQmlListModel::~QQmlListModel()
-{
- qDeleteAll(m_modelObjects);
-
- if (m_primary) {
- m_listModel->destroy();
- delete m_listModel;
-
- if (m_mainThread && m_agent) {
- m_agent->modelDestroyed();
- m_agent->release();
- }
- }
-
- m_listModel = nullptr;
-
- delete m_layout;
- m_layout = nullptr;
-}
-
-QQmlListModel *QQmlListModel::createWithOwner(QQmlListModel *newOwner)
-{
- QQmlListModel *model = new QQmlListModel;
-
- model->m_mainThread = newOwner->m_mainThread;
- model->m_engine = newOwner->m_engine;
- model->m_agent = newOwner->m_agent;
- model->m_dynamicRoles = newOwner->m_dynamicRoles;
-
- if (model->m_mainThread && model->m_agent)
- model->m_agent->addref();
-
- QQmlEngine::setContextForObject(model, QQmlEngine::contextForObject(newOwner));
-
- return model;
-}
-
-QV4::ExecutionEngine *QQmlListModel::engine() const
-{
- if (m_engine == nullptr) {
- m_engine = qmlEngine(this)->handle();
- }
-
- return m_engine;
-}
-
-bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
-{
- Q_ASSERT(src->m_dynamicRoles && target->m_dynamicRoles);
-
- bool hasChanges = false;
-
- target->m_roles = src->m_roles;
-
- // Build hash of elements <-> uid for each of the lists
- QHash<int, ElementSync> elementHash;
- for (int i = 0 ; i < target->m_modelObjects.count(); ++i) {
- DynamicRoleModelNode *e = target->m_modelObjects.at(i);
- int uid = e->getUid();
- ElementSync sync;
- sync.target = e;
- sync.targetIndex = i;
- elementHash.insert(uid, sync);
- }
- for (int i = 0 ; i < src->m_modelObjects.count(); ++i) {
- DynamicRoleModelNode *e = src->m_modelObjects.at(i);
- int uid = e->getUid();
-
- QHash<int, ElementSync>::iterator it = elementHash.find(uid);
- if (it == elementHash.end()) {
- ElementSync sync;
- sync.src = e;
- sync.srcIndex = i;
- elementHash.insert(uid, sync);
- } else {
- ElementSync &sync = it.value();
- sync.src = e;
- sync.srcIndex = i;
- }
- }
-
- // Get list of elements that are in the target but no longer in the source. These get deleted first.
- int rowsRemoved = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = target->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.targetIndex >= 0);
- // need to update the targetIndex, to keep it correct after removals
- s.targetIndex -= rowsRemoved;
- if (s.src == nullptr) {
- Q_ASSERT(s.targetIndex == i);
- hasChanges = true;
- target->beginRemoveRows(QModelIndex(), i, i);
- target->m_modelObjects.remove(i, 1);
- target->endRemoveRows();
- delete s.target;
- ++rowsRemoved;
- --i;
- continue;
- }
- }
-
- // Clear the target list, and append in correct order from the source
- target->m_modelObjects.clear();
- for (int i = 0 ; i < src->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = src->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- DynamicRoleModelNode *targetElement = s.target;
- if (targetElement == nullptr) {
- targetElement = new DynamicRoleModelNode(target, element->getUid());
- }
- s.changedRoles = DynamicRoleModelNode::sync(element, targetElement);
- target->m_modelObjects.append(targetElement);
- }
-
- // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts,
- // so the model indices can't be out of bounds
- //
- // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
- // model indices are updated correctly
- int rowsInserted = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = target->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- s.srcIndex += rowsInserted;
- if (s.srcIndex != s.targetIndex) {
- if (s.targetIndex == -1) {
- target->beginInsertRows(QModelIndex(), i, i);
- target->endInsertRows();
- } else {
- target->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex);
- target->endMoveRows();
- }
- hasChanges = true;
- ++rowsInserted;
- }
- if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) {
- QModelIndex idx = target->createIndex(i, 0);
- emit target->dataChanged(idx, idx, s.changedRoles);
- hasChanges = true;
- }
- }
- return hasChanges;
-}
-
-void QQmlListModel::emitItemsChanged(int index, int count, const QVector<int> &roles)
-{
- if (count <= 0)
- return;
-
- if (m_mainThread)
- emit dataChanged(createIndex(index, 0), createIndex(index + count - 1, 0), roles);;
-}
-
-void QQmlListModel::emitItemsAboutToBeInserted(int index, int count)
-{
- Q_ASSERT(index >= 0 && count >= 0);
- if (m_mainThread)
- beginInsertRows(QModelIndex(), index, index + count - 1);
-}
-
-void QQmlListModel::emitItemsInserted()
-{
- if (m_mainThread) {
- endInsertRows();
- emit countChanged();
- }
-}
-
-QQmlListModelWorkerAgent *QQmlListModel::agent()
-{
- if (m_agent)
- return m_agent;
-
- m_agent = new QQmlListModelWorkerAgent(this);
- return m_agent;
-}
-
-QModelIndex QQmlListModel::index(int row, int column, const QModelIndex &parent) const
-{
- return row >= 0 && row < count() && column == 0 && !parent.isValid()
- ? createIndex(row, column)
- : QModelIndex();
-}
-
-int QQmlListModel::rowCount(const QModelIndex &parent) const
-{
- return !parent.isValid() ? count() : 0;
-}
-
-QVariant QQmlListModel::data(const QModelIndex &index, int role) const
-{
- return data(index.row(), role);
-}
-
-bool QQmlListModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- const int row = index.row();
- if (row >= count() || row < 0)
- return false;
-
- if (m_dynamicRoles) {
- const QByteArray property = m_roles.at(role).toUtf8();
- if (m_modelObjects[row]->setValue(property, value)) {
- emitItemsChanged(row, 1, QVector<int>(1, role));
- return true;
- }
- } else {
- const ListLayout::Role &r = m_listModel->getExistingRole(role);
- const int roleIndex = m_listModel->setOrCreateProperty(row, r.name, value);
- if (roleIndex != -1) {
- emitItemsChanged(row, 1, QVector<int>(1, role));
- return true;
- }
- }
-
- return false;
-}
-
-QVariant QQmlListModel::data(int index, int role) const
-{
- QVariant v;
-
- if (index >= count() || index < 0)
- return v;
-
- if (m_dynamicRoles)
- v = m_modelObjects[index]->getValue(m_roles[role]);
- else
- v = m_listModel->getProperty(index, role, this, engine());
-
- return v;
-}
-
-QHash<int, QByteArray> QQmlListModel::roleNames() const
-{
- QHash<int, QByteArray> roleNames;
-
- if (m_dynamicRoles) {
- for (int i = 0 ; i < m_roles.count() ; ++i)
- roleNames.insert(i, m_roles.at(i).toUtf8());
- } else {
- for (int i = 0 ; i < m_listModel->roleCount() ; ++i) {
- const ListLayout::Role &r = m_listModel->getExistingRole(i);
- roleNames.insert(i, r.name.toUtf8());
- }
- }
-
- return roleNames;
-}
-
-/*!
- \qmlproperty bool ListModel::dynamicRoles
-
- By default, the type of a role is fixed the first time
- the role is used. For example, if you create a role called
- "data" and assign a number to it, you can no longer assign
- a string to the "data" role. However, when the dynamicRoles
- property is enabled, the type of a given role is not fixed
- and can be different between elements.
-
- The dynamicRoles property must be set before any data is
- added to the ListModel, and must be set from the main
- thread.
-
- A ListModel that has data statically defined (via the
- ListElement QML syntax) cannot have the dynamicRoles
- property enabled.
-
- There is a significant performance cost to using a
- ListModel with dynamic roles enabled. The cost varies
- from platform to platform but is typically somewhere
- between 4-6x slower than using static role types.
-
- Due to the performance cost of using dynamic roles,
- they are disabled by default.
-*/
-void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
-{
- if (m_mainThread && m_agent == nullptr) {
- if (enableDynamicRoles) {
- if (m_layout->roleCount())
- qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty");
- else
- m_dynamicRoles = true;
- } else {
- if (m_roles.count()) {
- qmlWarning(this) << tr("unable to enable static roles as this model is not empty");
- } else {
- m_dynamicRoles = false;
- }
- }
- } else {
- qmlWarning(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created");
- }
-}
-
-/*!
- \qmlproperty int ListModel::count
- The number of data entries in the model.
-*/
-int QQmlListModel::count() const
-{
- return m_dynamicRoles ? m_modelObjects.count() : m_listModel->elementCount();
-}
-
-/*!
- \qmlmethod ListModel::clear()
-
- Deletes all content from the model.
-
- \sa append(), remove()
-*/
-void QQmlListModel::clear()
-{
- removeElements(0, count());
-}
-
-/*!
- \qmlmethod ListModel::remove(int index, int count = 1)
-
- Deletes the content at \a index from the model.
-
- \sa clear()
-*/
-void QQmlListModel::remove(QQmlV4Function *args)
-{
- int argLength = args->length();
-
- if (argLength == 1 || argLength == 2) {
- QV4::Scope scope(args->v4engine());
- int index = QV4::ScopedValue(scope, (*args)[0])->toInt32();
- int removeCount = (argLength == 2 ? QV4::ScopedValue(scope, (*args)[1])->toInt32() : 1);
-
- if (index < 0 || index+removeCount > count() || removeCount <= 0) {
- qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count());
- return;
- }
-
- removeElements(index, removeCount);
- } else {
- qmlWarning(this) << tr("remove: incorrect number of arguments");
- }
-}
-
-void QQmlListModel::removeElements(int index, int removeCount)
-{
- Q_ASSERT(index >= 0 && removeCount >= 0);
-
- if (!removeCount)
- return;
-
- if (m_mainThread)
- beginRemoveRows(QModelIndex(), index, index + removeCount - 1);
-
- QVector<std::function<void()>> toDestroy;
- if (m_dynamicRoles) {
- for (int i=0 ; i < removeCount ; ++i) {
- auto modelObject = m_modelObjects[index+i];
- toDestroy.append([modelObject](){
- delete modelObject;
- });
- }
- m_modelObjects.remove(index, removeCount);
- } else {
- toDestroy = m_listModel->remove(index, removeCount);
- }
-
- if (m_mainThread) {
- endRemoveRows();
- emit countChanged();
- }
- for (const auto &destroyer : toDestroy)
- destroyer();
-}
-
-/*!
- \qmlmethod ListModel::insert(int index, jsobject dict)
-
- Adds a new item to the list model at position \a index, with the
- values in \a dict.
-
- \code
- fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
- \endcode
-
- The \a index must be to an existing item in the list, or one past
- the end of the list (equivalent to append).
-
- \sa set(), append()
-*/
-
-void QQmlListModel::insert(QQmlV4Function *args)
-{
- if (args->length() == 2) {
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue arg0(scope, (*args)[0]);
- int index = arg0->toInt32();
-
- if (index < 0 || index > count()) {
- qmlWarning(this) << tr("insert: index %1 out of range").arg(index);
- return;
- }
-
- QV4::ScopedObject argObject(scope, (*args)[1]);
- QV4::ScopedArrayObject objectArray(scope, (*args)[1]);
- if (objectArray) {
- QV4::ScopedObject argObject(scope);
-
- int objectArrayLength = objectArray->getLength();
- emitItemsAboutToBeInserted(index, objectArrayLength);
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->get(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.insert(index+i, DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->insert(index+i, argObject);
- }
- }
- emitItemsInserted();
- } else if (argObject) {
- emitItemsAboutToBeInserted(index, 1);
-
- if (m_dynamicRoles) {
- m_modelObjects.insert(index, DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->insert(index, argObject);
- }
-
- emitItemsInserted();
- } else {
- qmlWarning(this) << tr("insert: value is not an object");
- }
- } else {
- qmlWarning(this) << tr("insert: value is not an object");
- }
-}
-
-/*!
- \qmlmethod ListModel::move(int from, int to, int n)
-
- Moves \a n items \a from one position \a to another.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the list:
-
- \code
- fruitModel.move(0, fruitModel.count - 3, 3)
- \endcode
-
- \sa append()
-*/
-void QQmlListModel::move(int from, int to, int n)
-{
- if (n == 0 || from == to)
- return;
- if (!canMove(from, to, n)) {
- qmlWarning(this) << tr("move: out of range");
- return;
- }
-
- if (m_mainThread)
- beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to);
-
- if (m_dynamicRoles) {
-
- int realFrom = from;
- int realTo = to;
- int realN = n;
-
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- realFrom = tto;
- realTo = tto+n;
- realN = tfrom-tto;
- }
-
- QPODVector<DynamicRoleModelNode *, 4> store;
- for (int i=0 ; i < (realTo-realFrom) ; ++i)
- store.append(m_modelObjects[realFrom+realN+i]);
- for (int i=0 ; i < realN ; ++i)
- store.append(m_modelObjects[realFrom+i]);
- for (int i=0 ; i < store.count() ; ++i)
- m_modelObjects[realFrom+i] = store[i];
-
- } else {
- m_listModel->move(from, to, n);
- }
-
- if (m_mainThread)
- endMoveRows();
-}
-
-/*!
- \qmlmethod ListModel::append(jsobject dict)
-
- Adds a new item to the end of the list model, with the
- values in \a dict.
-
- \code
- fruitModel.append({"cost": 5.95, "name":"Pizza"})
- \endcode
-
- \sa set(), remove()
-*/
-void QQmlListModel::append(QQmlV4Function *args)
-{
- if (args->length() == 1) {
- QV4::Scope scope(args->v4engine());
- QV4::ScopedObject argObject(scope, (*args)[0]);
- QV4::ScopedArrayObject objectArray(scope, (*args)[0]);
-
- if (objectArray) {
- QV4::ScopedObject argObject(scope);
-
- int objectArrayLength = objectArray->getLength();
- if (objectArrayLength > 0) {
- int index = count();
- emitItemsAboutToBeInserted(index, objectArrayLength);
-
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->get(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->append(argObject);
- }
- }
-
- emitItemsInserted();
- }
- } else if (argObject) {
- int index;
-
- if (m_dynamicRoles) {
- index = m_modelObjects.count();
- emitItemsAboutToBeInserted(index, 1);
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- index = m_listModel->elementCount();
- emitItemsAboutToBeInserted(index, 1);
- m_listModel->append(argObject);
- }
-
- emitItemsInserted();
- } else {
- qmlWarning(this) << tr("append: value is not an object");
- }
- } else {
- qmlWarning(this) << tr("append: value is not an object");
- }
-}
-
-/*!
- \qmlmethod object ListModel::get(int index)
-
- Returns the item at \a index in the list model. This allows the item
- data to be accessed or modified from JavaScript:
-
- \code
- Component.onCompleted: {
- fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
- console.log(fruitModel.get(0).cost);
- fruitModel.get(0).cost = 10.95;
- }
- \endcode
-
- The \a index must be an element in the list.
-
- Note that properties of the returned object that are themselves objects
- will also be models, and this get() method is used to access elements:
-
- \code
- fruitModel.append(..., "attributes":
- [{"name":"spikes","value":"7mm"},
- {"name":"color","value":"green"}]);
- fruitModel.get(0).attributes.get(1).value; // == "green"
- \endcode
-
- \warning The returned object is not guaranteed to remain valid. It
- should not be used in \l{Property Binding}{property bindings}.
-
- \sa append()
-*/
-QJSValue QQmlListModel::get(int index) const
-{
- QV4::Scope scope(engine());
- QV4::ScopedValue result(scope, QV4::Value::undefinedValue());
-
- if (index >= 0 && index < count()) {
-
- if (m_dynamicRoles) {
- DynamicRoleModelNode *object = m_modelObjects[index];
- result = QV4::QObjectWrapper::wrap(scope.engine, object);
- } else {
- QObject *object = m_listModel->getOrCreateModelObject(const_cast<QQmlListModel *>(this), index);
- QQmlData *ddata = QQmlData::get(object);
- if (ddata->jsWrapper.isNullOrUndefined()) {
- result = scope.engine->memoryManager->allocate<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this));
- // Keep track of the QObjectWrapper in persistent value storage
- ddata->jsWrapper.set(scope.engine, result);
- } else {
- result = ddata->jsWrapper.value();
- }
- }
- }
-
- return QJSValue(engine(), result->asReturnedValue());
-}
-
-/*!
- \qmlmethod ListModel::set(int index, jsobject dict)
-
- Changes the item at \a index in the list model with the
- values in \a dict. Properties not appearing in \a dict
- are left unchanged.
-
- \code
- fruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
- \endcode
-
- If \a index is equal to count() then a new item is appended to the
- list. Otherwise, \a index must be an element in the list.
-
- \sa append()
-*/
-void QQmlListModel::set(int index, const QJSValue &value)
-{
- QV4::Scope scope(engine());
- QV4::ScopedObject object(scope, QJSValuePrivate::getValue(&value));
-
- if (!object) {
- qmlWarning(this) << tr("set: value is not an object");
- return;
- }
- if (index > count() || index < 0) {
- qmlWarning(this) << tr("set: index %1 out of range").arg(index);
- return;
- }
-
-
- if (index == count()) {
- emitItemsAboutToBeInserted(index, 1);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(object), this));
- } else {
- m_listModel->insert(index, object);
- }
-
- emitItemsInserted();
- } else {
-
- QVector<int> roles;
-
- if (m_dynamicRoles) {
- m_modelObjects[index]->updateValues(scope.engine->variantMapFromJS(object), roles);
- } else {
- m_listModel->set(index, object, &roles);
- }
-
- if (roles.count())
- emitItemsChanged(index, 1, roles);
- }
-}
-
-/*!
- \qmlmethod ListModel::setProperty(int index, string property, variant value)
-
- Changes the \a property of the item at \a index in the list model to \a value.
-
- \code
- fruitModel.setProperty(3, "cost", 5.95)
- \endcode
-
- The \a index must be an element in the list.
-
- \sa append()
-*/
-void QQmlListModel::setProperty(int index, const QString& property, const QVariant& value)
-{
- if (count() == 0 || index >= count() || index < 0) {
- qmlWarning(this) << tr("set: index %1 out of range").arg(index);
- return;
- }
-
- if (m_dynamicRoles) {
- int roleIndex = m_roles.indexOf(property);
- if (roleIndex == -1) {
- roleIndex = m_roles.count();
- m_roles.append(property);
- }
- if (m_modelObjects[index]->setValue(property.toUtf8(), value))
- emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
- } else {
- int roleIndex = m_listModel->setOrCreateProperty(index, property, value);
- if (roleIndex != -1)
- emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
- }
-}
-
-/*!
- \qmlmethod ListModel::sync()
-
- Writes any unsaved changes to the list model after it has been modified
- from a worker script.
-*/
-void QQmlListModel::sync()
-{
- // This is just a dummy method to make it look like sync() exists in
- // ListModel (and not just QQmlListModelWorkerAgent) and to let
- // us document sync().
- qmlWarning(this) << "List sync() can only be called from a WorkerScript";
-}
-
-bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
-{
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- const quint32 targetObjectIndex = binding->value.objectIndex;
- const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
- QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex);
- if (objName != listElementTypeName) {
- const QMetaObject *mo = resolveType(objName);
- if (mo != &QQmlListElement::staticMetaObject) {
- error(target, QQmlListModel::tr("ListElement: cannot contain nested elements"));
- return false;
- }
- listElementTypeName = objName; // cache right name for next time
- }
-
- if (!compilationUnit->stringAt(target->idNameIndex).isEmpty()) {
- error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
- return false;
- }
-
- const QV4::CompiledData::Binding *binding = target->bindingTable();
- for (quint32 i = 0; i < target->nBindings; ++i, ++binding) {
- QString propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (propName.isEmpty()) {
- error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements"));
- return false;
- }
- if (!verifyProperty(compilationUnit, binding))
- return false;
- }
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QString scriptStr = binding->valueAsScriptString(compilationUnit.data());
- if (!binding->isFunctionExpression() && !definesEmptyList(scriptStr)) {
- QByteArray script = scriptStr.toUtf8();
- bool ok;
- evaluateEnum(script, &ok);
- if (!ok) {
- error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool QQmlListModelParser::applyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex)
-{
- const QString elementName = compilationUnit->stringAt(binding->propertyNameIndex);
-
- bool roleSet = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- const quint32 targetObjectIndex = binding->value.objectIndex;
- const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
-
- ListModel *subModel = nullptr;
- if (outterElementIndex == -1) {
- subModel = model;
- } else {
- const ListLayout::Role &role = model->getOrCreateListRole(elementName);
- if (role.type == ListLayout::Role::List) {
- subModel = model->getListProperty(outterElementIndex, role);
- if (subModel == nullptr) {
- subModel = new ListModel(role.subLayout, nullptr);
- QVariant vModel = QVariant::fromValue(subModel);
- model->setOrCreateProperty(outterElementIndex, elementName, vModel);
- }
- }
- }
-
- int elementIndex = subModel ? subModel->appendElement() : -1;
-
- const QV4::CompiledData::Binding *subBinding = target->bindingTable();
- for (quint32 i = 0; i < target->nBindings; ++i, ++subBinding) {
- roleSet |= applyProperty(compilationUnit, subBinding, subModel, elementIndex);
- }
-
- } else {
- QVariant value;
-
- if (binding->isTranslationBinding()) {
- value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
- } else if (binding->evaluatesToString()) {
- value = binding->valueAsString(compilationUnit.data());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- value = binding->valueAsNumber(compilationUnit->constants);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
- value = binding->valueAsBoolean();
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- value = QVariant::fromValue(nullptr);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QString scriptStr = binding->valueAsScriptString(compilationUnit.data());
- if (definesEmptyList(scriptStr)) {
- const ListLayout::Role &role = model->getOrCreateListRole(elementName);
- ListModel *emptyModel = new ListModel(role.subLayout, nullptr);
- value = QVariant::fromValue(emptyModel);
- } else if (binding->isFunctionExpression()) {
- QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
- Q_ASSERT(id != QQmlBinding::Invalid);
-
- auto v4 = compilationUnit->engine;
- QV4::Scope scope(v4);
- // for now we do not provide a context object; data from the ListElement must be passed to the function
- QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr));
- QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id]));
-
- QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0);
-
- QJSValue v;
- QJSValuePrivate::setValue(&v, v4, result);
- value.setValue<QJSValue>(v);
- } else {
- QByteArray script = scriptStr.toUtf8();
- bool ok;
- value = evaluateEnum(script, &ok);
- }
- } else {
- Q_UNREACHABLE();
- }
-
- model->setOrCreateProperty(outterElementIndex, elementName, value);
- roleSet = true;
- }
- return roleSet;
-}
-
-void QQmlListModelParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- listElementTypeName = QString(); // unknown
-
- for (const QV4::CompiledData::Binding *binding : bindings) {
- QString propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (!propName.isEmpty()) { // isn't default property
- error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
- return;
- }
- if (!verifyProperty(compilationUnit, binding))
- return;
- }
-}
-
-void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
-
- rv->m_engine = qmlEngine(rv)->handle();
- rv->m_compilationUnit = compilationUnit;
-
- bool setRoles = false;
-
- for (const QV4::CompiledData::Binding *binding : bindings) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1);
- }
-
- if (setRoles == false)
- qmlWarning(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.";
-}
-
-bool QQmlListModelParser::definesEmptyList(const QString &s)
-{
- if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
- for (int i=1; i<s.length()-1; i++) {
- if (!s[i].isSpace())
- return false;
- }
- return true;
- }
- return false;
-}
-
-
-/*!
- \qmltype ListElement
- \instantiates QQmlListElement
- \inqmlmodule QtQml.Models
- \brief Defines a data item in a ListModel.
- \ingroup qtquick-models
-
- List elements are defined inside ListModel definitions, and represent items in a
- list that will be displayed using ListView or \l Repeater items.
-
- List elements are defined like other QML elements except that they contain
- a collection of \e role definitions instead of properties. Using the same
- syntax as property definitions, roles both define how the data is accessed
- and include the data itself.
-
- The names used for roles must begin with a lower-case letter and should be
- common to all elements in a given model. Values must be simple constants; either
- strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
- (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
-
- Beginning with Qt 5.11 ListElement also allows assigning a function declaration to
- a role. This allows the definition of ListElements with callable actions.
-
- \section1 Referencing Roles
-
- The role names are used by delegates to obtain data from list elements.
- Each role name is accessible in the delegate's scope, and refers to the
- corresponding role in the current element. Where a role name would be
- ambiguous to use, it can be accessed via the \l{ListView::}{model}
- property (e.g., \c{model.cost} instead of \c{cost}).
-
- \section1 Example Usage
-
- The following model defines a series of list elements, each of which
- contain "name" and "cost" roles and their associated values.
-
- \snippet qml/listmodel/listelements.qml model
-
- The delegate obtains the name and cost for each element by simply referring
- to \c name and \c cost:
-
- \snippet qml/listmodel/listelements.qml view
-
- \sa ListModel
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qqmllistmodel_p.cpp"
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
deleted file mode 100644
index 471e33aa5a..0000000000
--- a/src/qml/types/qqmllistmodel_p.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTMODEL_H
-#define QQMLLISTMODEL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qqml.h>
-#include <private/qqmlcustomparser_p.h>
-
-#include <QtCore/QObject>
-#include <QtCore/QStringList>
-#include <QtCore/QHash>
-#include <QtCore/QList>
-#include <QtCore/QVariant>
-#include <QtCore/qabstractitemmodel.h>
-
-#include <private/qv4engine_p.h>
-#include <private/qpodvector_p.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class QQmlListModelWorkerAgent;
-class ListModel;
-class ListLayout;
-
-namespace QV4 {
-struct ModelObject;
-}
-
-class Q_QML_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
-
-public:
- QQmlListModel(QObject *parent=nullptr);
- ~QQmlListModel();
-
- QModelIndex index(int row, int column, const QModelIndex &parent) const override;
- int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- QHash<int,QByteArray> roleNames() const override;
-
- QVariant data(int index, int role) const;
- int count() const;
-
- Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QJSValue get(int index) const;
- Q_INVOKABLE void set(int index, const QJSValue &value);
- Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
- Q_INVOKABLE void move(int from, int to, int count);
- Q_INVOKABLE void sync();
-
- QQmlListModelWorkerAgent *agent();
-
- bool dynamicRoles() const { return m_dynamicRoles; }
- void setDynamicRoles(bool enableDynamicRoles);
-
-Q_SIGNALS:
- void countChanged();
-
-private:
- friend class QQmlListModelParser;
- friend class QQmlListModelWorkerAgent;
- friend class ModelObject;
- friend struct QV4::ModelObject;
- friend class ModelNodeMetaObject;
- friend class ListModel;
- friend class ListElement;
- friend class DynamicRoleModelNode;
- friend class DynamicRoleModelNodeMetaObject;
- friend struct StringOrTranslation;
-
- // Constructs a flat list model for a worker agent
- QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent);
- QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::ExecutionEngine *engine, QObject *parent=nullptr);
-
- QV4::ExecutionEngine *engine() const;
-
- inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
-
- QQmlListModelWorkerAgent *m_agent;
- mutable QV4::ExecutionEngine *m_engine;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
- bool m_mainThread;
- bool m_primary;
-
- bool m_dynamicRoles;
-
- ListLayout *m_layout;
- ListModel *m_listModel;
-
- QVector<class DynamicRoleModelNode *> m_modelObjects;
- QVector<QString> m_roles;
-
- struct ElementSync
- {
- DynamicRoleModelNode *src = nullptr;
- DynamicRoleModelNode *target = nullptr;
- int srcIndex = -1;
- int targetIndex = -1;
- QVector<int> changedRoles;
- };
-
- static bool sync(QQmlListModel *src, QQmlListModel *target);
- static QQmlListModel *createWithOwner(QQmlListModel *newOwner);
-
- void emitItemsChanged(int index, int count, const QVector<int> &roles);
- void emitItemsAboutToBeInserted(int index, int count);
- void emitItemsInserted();
-
- void removeElements(int index, int removeCount);
-};
-
-// ### FIXME
-class QQmlListElement : public QObject
-{
-Q_OBJECT
-};
-
-class QQmlListModelParser : public QQmlCustomParser
-{
-public:
- enum PropertyType {
- Invalid,
- Boolean,
- Number,
- String,
- Script
- };
-
-
- QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
-
- void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
- void applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
-
-private:
- bool verifyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding);
- // returns true if a role was set
- bool applyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex);
-
- static bool definesEmptyList(const QString &);
-
- QString listElementTypeName;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlListModel)
-QML_DECLARE_TYPE(QQmlListElement)
-
-#endif // QQMLLISTMODEL_H
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
deleted file mode 100644
index 2876c71de6..0000000000
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTMODEL_P_P_H
-#define QQMLLISTMODEL_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qqmllistmodel_p.h"
-#include <private/qqmlengine_p.h>
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <qqml.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class DynamicRoleModelNode;
-
-class DynamicRoleModelNodeMetaObject : public QQmlOpenMetaObject
-{
-public:
- DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object);
- ~DynamicRoleModelNodeMetaObject();
-
- bool m_enabled;
-
-protected:
- void propertyWrite(int index) override;
- void propertyWritten(int index) override;
-
-private:
- DynamicRoleModelNode *m_owner;
-};
-
-class DynamicRoleModelNode : public QObject
-{
- Q_OBJECT
-public:
- DynamicRoleModelNode(QQmlListModel *owner, int uid);
-
- static DynamicRoleModelNode *create(const QVariantMap &obj, QQmlListModel *owner);
-
- void updateValues(const QVariantMap &object, QVector<int> &roles);
-
- QVariant getValue(const QString &name) const
- {
- return m_meta->value(name.toUtf8());
- }
-
- bool setValue(const QByteArray &name, const QVariant &val)
- {
- return m_meta->setValue(name, val);
- }
-
- void setNodeUpdatesEnabled(bool enable)
- {
- m_meta->m_enabled = enable;
- }
-
- int getUid() const
- {
- return m_uid;
- }
-
- static QVector<int> sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target);
-
-private:
- QQmlListModel *m_owner;
- int m_uid;
- DynamicRoleModelNodeMetaObject *m_meta;
-
- friend class DynamicRoleModelNodeMetaObject;
-};
-
-class ModelNodeMetaObject : public QQmlOpenMetaObject
-{
-public:
- ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex);
- ~ModelNodeMetaObject();
-
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *object) override;
-
- static ModelNodeMetaObject *get(QObject *obj);
-
- bool m_enabled;
- QQmlListModel *m_model;
- int m_elementIndex;
-
- void updateValues();
- void updateValues(const QVector<int> &roles);
-
- bool initialized() const { return m_initialized; }
-
-protected:
- void propertyWritten(int index) override;
-
-private:
- using QQmlOpenMetaObject::setValue;
-
- void emitDirectNotifies(const int *changedRoles, int roleCount);
-
- void initialize();
- bool m_initialized;
-};
-
-namespace QV4 {
-
-namespace Heap {
-
-struct ModelObject : public QObjectWrapper {
- void init(QObject *object, QQmlListModel *model)
- {
- QObjectWrapper::init(object);
- m_model = model;
- QObjectPrivate *op = QObjectPrivate::get(object);
- m_nodeModelMetaObject = static_cast<ModelNodeMetaObject *>(op->metaObject);
- }
- void destroy() { QObjectWrapper::destroy(); }
- int elementIndex() const { return m_nodeModelMetaObject->m_elementIndex; }
- QQmlListModel *m_model;
- ModelNodeMetaObject *m_nodeModelMetaObject;
-};
-
-}
-
-struct ModelObject : public QObjectWrapper
-{
- V4_OBJECT2(ModelObject, QObjectWrapper)
- V4_NEEDS_DESTROY
-
- ListModel *listModel() const { return d()->m_model->m_listModel; }
-
-protected:
- static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
- static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
- static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
- static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
-};
-
-} // namespace QV4
-
-class ListLayout
-{
-public:
- ListLayout() : currentBlock(0), currentBlockOffset(0) {}
- ListLayout(const ListLayout *other);
- ~ListLayout();
-
- class Role
- {
- public:
-
- Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {}
- explicit Role(const Role *other);
- ~Role();
-
- // This enum must be kept in sync with the roleTypeNames variable in qqmllistmodel.cpp
- enum DataType
- {
- Invalid = -1,
-
- String,
- Number,
- Bool,
- List,
- QObject,
- VariantMap,
- DateTime,
- Function,
-
- MaxDataType
- };
-
- QString name;
- DataType type;
- int blockIndex;
- int blockOffset;
- int index;
- ListLayout *subLayout;
- };
-
- const Role *getRoleOrCreate(const QString &key, const QVariant &data);
- const Role &getRoleOrCreate(QV4::String *key, Role::DataType type);
- const Role &getRoleOrCreate(const QString &key, Role::DataType type);
-
- const Role &getExistingRole(int index) const { return *roles.at(index); }
- const Role *getExistingRole(const QString &key) const;
- const Role *getExistingRole(QV4::String *key) const;
-
- int roleCount() const { return roles.count(); }
-
- static void sync(ListLayout *src, ListLayout *target);
-
-private:
- const Role &createRole(const QString &key, Role::DataType type);
-
- int currentBlock;
- int currentBlockOffset;
- QVector<Role *> roles;
- QStringHash<Role *> roleHash;
-};
-
-struct StringOrTranslation
-{
- explicit StringOrTranslation(const QString &s);
- explicit StringOrTranslation(const QV4::CompiledData::Binding *binding);
- ~StringOrTranslation();
- bool isSet() const { return d.flag(); }
- bool isTranslation() const { return d.isT2(); }
- void setString(const QString &s);
- void setTranslation(const QV4::CompiledData::Binding *binding);
- QString toString(const QQmlListModel *owner) const;
- QString asString() const;
-private:
- void clear();
- QBiPointer<QStringData, const QV4::CompiledData::Binding> d;
-};
-
-/*!
-\internal
-*/
-class ListElement
-{
-public:
-
- ListElement();
- ListElement(int existingUid);
- ~ListElement();
-
- static QVector<int> sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout);
-
- enum
- {
- BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelNodeMetaObject *)
- };
-
-private:
-
- void destroy(ListLayout *layout);
-
- int setVariantProperty(const ListLayout::Role &role, const QVariant &d);
-
- int setJsProperty(const ListLayout::Role &role, const QV4::Value &d, QV4::ExecutionEngine *eng);
-
- int setStringProperty(const ListLayout::Role &role, const QString &s);
- int setDoubleProperty(const ListLayout::Role &role, double n);
- int setBoolProperty(const ListLayout::Role &role, bool b);
- int setListProperty(const ListLayout::Role &role, ListModel *m);
- int setQObjectProperty(const ListLayout::Role &role, QObject *o);
- int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o);
- int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
- int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
- int setFunctionProperty(const ListLayout::Role &role, const QJSValue &f);
- int setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b);
-
- void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
- void setDoublePropertyFast(const ListLayout::Role &role, double n);
- void setBoolPropertyFast(const ListLayout::Role &role, bool b);
- void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o);
- void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
- void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o);
- void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
- void setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f);
-
- void clearProperty(const ListLayout::Role &role);
-
- QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
- ListModel *getListProperty(const ListLayout::Role &role);
- StringOrTranslation *getStringProperty(const ListLayout::Role &role);
- QObject *getQObjectProperty(const ListLayout::Role &role);
- QPointer<QObject> *getGuardProperty(const ListLayout::Role &role);
- QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
- QDateTime *getDateTimeProperty(const ListLayout::Role &role);
- QJSValue *getFunctionProperty(const ListLayout::Role &role);
-
- inline char *getPropertyMemory(const ListLayout::Role &role);
-
- int getUid() const { return uid; }
-
- ModelNodeMetaObject *objectCache();
-
- char data[BLOCK_SIZE];
- ListElement *next;
-
- int uid;
- QObject *m_objectCache;
-
- friend class ListModel;
-};
-
-/*!
-\internal
-*/
-class ListModel
-{
-public:
-
- ListModel(ListLayout *layout, QQmlListModel *modelCache);
- ~ListModel() {}
-
- void destroy();
-
- int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data);
- int setExistingProperty(int uid, const QString &key, const QV4::Value &data, QV4::ExecutionEngine *eng);
-
- QVariant getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
- ListModel *getListProperty(int elementIndex, const ListLayout::Role &role);
-
- int roleCount() const
- {
- return m_layout->roleCount();
- }
-
- const ListLayout::Role &getExistingRole(int index) const
- {
- return m_layout->getExistingRole(index);
- }
-
- const ListLayout::Role *getExistingRole(QV4::String *key) const
- {
- return m_layout->getExistingRole(key);
- }
-
- const ListLayout::Role &getOrCreateListRole(const QString &name)
- {
- return m_layout->getRoleOrCreate(name, ListLayout::Role::List);
- }
-
- int elementCount() const
- {
- return elements.count();
- }
-
- void set(int elementIndex, QV4::Object *object, QVector<int> *roles);
- void set(int elementIndex, QV4::Object *object);
-
- int append(QV4::Object *object);
- void insert(int elementIndex, QV4::Object *object);
-
- Q_REQUIRED_RESULT QVector<std::function<void()>> remove(int index, int count);
-
- int appendElement();
- void insertElement(int index);
-
- void move(int from, int to, int n);
-
- static bool sync(ListModel *src, ListModel *target);
-
- QObject *getOrCreateModelObject(QQmlListModel *model, int elementIndex);
-
-private:
- QPODVector<ListElement *, 4> elements;
- ListLayout *m_layout;
-
- QQmlListModel *m_modelCache;
-
- struct ElementSync
- {
- ListElement *src = nullptr;
- ListElement *target = nullptr;
- int srcIndex = -1;
- int targetIndex = -1;
- QVector<int> changedRoles;
- };
-
- void newElement(int index);
-
- void updateCacheIndices(int start = 0, int end = -1);
-
- friend class ListElement;
- friend class QQmlListModelWorkerAgent;
- friend class QQmlListModelParser;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(ListModel *);
-
-#endif // QQUICKLISTMODEL_P_P_H
diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qml/types/qqmllistmodelworkeragent.cpp
deleted file mode 100644
index f7cb08dcf4..0000000000
--- a/src/qml/types/qqmllistmodelworkeragent.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistmodelworkeragent_p.h"
-#include "qqmllistmodel_p_p.h"
-#include <private/qqmldata_p.h>
-#include <private/qqmlengine_p.h>
-#include <qqmlinfo.h>
-
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-
-
-QT_BEGIN_NAMESPACE
-
-QQmlListModelWorkerAgent::Sync::~Sync()
-{
-}
-
-QQmlListModelWorkerAgent::QQmlListModelWorkerAgent(QQmlListModel *model)
-: m_ref(1), m_orig(model), m_copy(new QQmlListModel(model, this))
-{
-}
-
-QQmlListModelWorkerAgent::~QQmlListModelWorkerAgent()
-{
- mutex.lock();
- syncDone.wakeAll();
- mutex.unlock();
-}
-
-void QQmlListModelWorkerAgent::setEngine(QV4::ExecutionEngine *eng)
-{
- m_copy->m_engine = eng;
-}
-
-void QQmlListModelWorkerAgent::addref()
-{
- m_ref.ref();
-}
-
-void QQmlListModelWorkerAgent::release()
-{
- bool del = !m_ref.deref();
-
- if (del)
- deleteLater();
-}
-
-void QQmlListModelWorkerAgent::modelDestroyed()
-{
- m_orig = nullptr;
-}
-
-int QQmlListModelWorkerAgent::count() const
-{
- return m_copy->count();
-}
-
-void QQmlListModelWorkerAgent::clear()
-{
- m_copy->clear();
-}
-
-void QQmlListModelWorkerAgent::remove(QQmlV4Function *args)
-{
- m_copy->remove(args);
-}
-
-void QQmlListModelWorkerAgent::append(QQmlV4Function *args)
-{
- m_copy->append(args);
-}
-
-void QQmlListModelWorkerAgent::insert(QQmlV4Function *args)
-{
- m_copy->insert(args);
-}
-
-QJSValue QQmlListModelWorkerAgent::get(int index) const
-{
- return m_copy->get(index);
-}
-
-void QQmlListModelWorkerAgent::set(int index, const QJSValue &value)
-{
- m_copy->set(index, value);
-}
-
-void QQmlListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
-{
- m_copy->setProperty(index, property, value);
-}
-
-void QQmlListModelWorkerAgent::move(int from, int to, int count)
-{
- m_copy->move(from, to, count);
-}
-
-void QQmlListModelWorkerAgent::sync()
-{
- Sync *s = new Sync(m_copy);
-
- mutex.lock();
- QCoreApplication::postEvent(this, s);
- syncDone.wait(&mutex);
- mutex.unlock();
-}
-
-bool QQmlListModelWorkerAgent::event(QEvent *e)
-{
- if (e->type() == QEvent::User) {
- bool cc = false;
- QMutexLocker locker(&mutex);
- if (m_orig) {
- Sync *s = static_cast<Sync *>(e);
-
- cc = (m_orig->count() != s->list->count());
-
- Q_ASSERT(m_orig->m_dynamicRoles == s->list->m_dynamicRoles);
- if (m_orig->m_dynamicRoles)
- QQmlListModel::sync(s->list, m_orig);
- else
- ListModel::sync(s->list->m_listModel, m_orig->m_listModel);
- }
-
- syncDone.wakeAll();
- locker.unlock();
-
- if (cc)
- emit m_orig->countChanged();
- return true;
- }
-
- return QObject::event(e);
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmllistmodelworkeragent_p.cpp"
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
deleted file mode 100644
index 69d1785618..0000000000
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKLISTMODELWORKERAGENT_P_H
-#define QQUICKLISTMODELWORKERAGENT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qqml.h>
-
-#include <QEvent>
-#include <QMutex>
-#include <QWaitCondition>
-
-#include <private/qv8engine_p.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class QQmlListModel;
-
-class QQmlListModelWorkerAgent : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count)
-
-public:
- QQmlListModelWorkerAgent(QQmlListModel *);
- ~QQmlListModelWorkerAgent();
- void setEngine(QV4::ExecutionEngine *eng);
-
- void addref();
- void release();
-
- int count() const;
-
- Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QJSValue get(int index) const;
- Q_INVOKABLE void set(int index, const QJSValue &value);
- Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
- Q_INVOKABLE void move(int from, int to, int count);
- Q_INVOKABLE void sync();
-
- struct VariantRef
- {
- VariantRef() : a(nullptr) {}
- VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
- VariantRef(QQmlListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
- ~VariantRef() { if (a) a->release(); }
-
- VariantRef &operator=(const VariantRef &o) {
- if (o.a) o.a->addref();
- if (a) a->release();
- a = o.a;
- return *this;
- }
-
- QQmlListModelWorkerAgent *a;
- };
-
- void modelDestroyed();
-protected:
- bool event(QEvent *) override;
-
-private:
- friend class QQuickWorkerScriptEnginePrivate;
- friend class QQmlListModel;
-
- struct Sync : public QEvent {
- Sync(QQmlListModel *l)
- : QEvent(QEvent::User)
- , list(l)
- {}
- ~Sync();
- QQmlListModel *list;
- };
-
- QAtomicInt m_ref;
- QQmlListModel *m_orig;
- QQmlListModel *m_copy;
- QMutex mutex;
- QWaitCondition syncDone;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QQmlListModelWorkerAgent::VariantRef)
-
-#endif // QQUICKLISTMODELWORKERAGENT_P_H
-
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
deleted file mode 100644
index 840b435d18..0000000000
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlmodelsmodule_p.h"
-#include <QtCore/qitemselectionmodel.h>
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#endif
-#if QT_CONFIG(qml_delegate_model)
-#include <private/qqmldelegatemodel_p.h>
-#include <private/qqmldelegatecomponent_p.h>
-#endif
-#include <private/qqmlobjectmodel_p.h>
-#include <private/qqmltablemodel_p.h>
-#include <private/qqmltablemodelcolumn_p.h>
-#include <private/qqmlinstantiator_p.h>
-#include <private/qquickpackage_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-void QQmlModelsModule::registerQmlTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
- qmlRegisterType<QQmlInstantiator>("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1
- qmlRegisterType<QQmlInstanceModel>();
-}
-
-void QQmlModelsModule::registerQuickTypes()
-{
- // Don't add anything here. These are only for backwards compatibility.
-
- const char uri[] = "QtQuick";
-
- qmlRegisterType<QQmlInstantiator>(uri, 2, 1, "Instantiator");
- qmlRegisterType<QQmlInstanceModel>();
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 0, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 0, "ListModel", new QQmlListModelParser);
-#endif
- qmlRegisterType<QQuickPackage>(uri, 2, 0, "Package");
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 0, "VisualDataModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 0, "VisualDataGroup");
-#endif
- qmlRegisterType<QQmlObjectModel>(uri, 2, 0, "VisualItemModel");
-}
-
-#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-void QQmlModelsModule::defineModule()
-{
- const char uri[] = "QtQml.Models";
-
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
-#endif
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
-#endif
- qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
- qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
-
- qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
-
- qmlRegisterType<QQuickPackage>(uri, 2, 14, "Package");
- qmlRegisterType<QQmlInstantiator>(uri, 2, 14, "Instantiator");
- qmlRegisterType<QQmlInstanceModel>();
-}
-
-void QQmlModelsModule::defineLabsModule()
-{
- const char uri[] = "Qt.labs.qmlmodels";
-
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterUncreatableType<QQmlAbstractDelegateComponent>(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent."));
- qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
- qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
-#endif
- qmlRegisterType<QQmlTableModel>(uri, 1, 0, "TableModel");
- qmlRegisterType<QQmlTableModelColumn>(uri, 1, 0, "TableModelColumn");
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
deleted file mode 100644
index b6330b4295..0000000000
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlobjectmodel_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtQml/qqmlcontext.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlinfo.h>
-
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qobject_p.h>
-#include <private/qpodvector_p.h>
-
-#include <QtCore/qhash.h>
-#include <QtCore/qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-QHash<QObject*, QQmlObjectModelAttached*> QQmlObjectModelAttached::attachedProperties;
-
-
-class QQmlObjectModelPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QQmlObjectModel)
-public:
- class Item {
- public:
- Item(QObject *i) : item(i), ref(0) {}
-
- void addRef() { ++ref; }
- bool deref() { return --ref == 0; }
-
- QObject *item;
- int ref;
- };
-
- QQmlObjectModelPrivate() : QObjectPrivate(), moveId(0) {}
-
- static void children_append(QQmlListProperty<QObject> *prop, QObject *item) {
- int index = static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count();
- static_cast<QQmlObjectModelPrivate *>(prop->data)->insert(index, item);
- }
-
- static int children_count(QQmlListProperty<QObject> *prop) {
- return static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count();
- }
-
- static QObject *children_at(QQmlListProperty<QObject> *prop, int index) {
- return static_cast<QQmlObjectModelPrivate *>(prop->data)->children.at(index).item;
- }
-
- static void children_clear(QQmlListProperty<QObject> *prop) {
- static_cast<QQmlObjectModelPrivate *>(prop->data)->clear();
- }
-
- void insert(int index, QObject *item) {
- Q_Q(QQmlObjectModel);
- children.insert(index, Item(item));
- for (int i = index; i < children.count(); ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(i);
- }
- QQmlChangeSet changeSet;
- changeSet.insert(index, 1);
- emit q->modelUpdated(changeSet, false);
- emit q->countChanged();
- emit q->childrenChanged();
- }
-
- void move(int from, int to, int n) {
- Q_Q(QQmlObjectModel);
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- from = tto;
- to = tto+n;
- n = tfrom-tto;
- }
-
- QPODVector<QQmlObjectModelPrivate::Item, 4> store;
- for (int i = 0; i < to - from; ++i)
- store.append(children[from + n + i]);
- for (int i = 0; i < n; ++i)
- store.append(children[from + i]);
-
- for (int i = 0; i < store.count(); ++i) {
- children[from + i] = store[i];
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(from + i).item);
- attached->setIndex(from + i);
- }
-
- QQmlChangeSet changeSet;
- changeSet.move(from, to, n, ++moveId);
- emit q->modelUpdated(changeSet, false);
- emit q->childrenChanged();
- }
-
- void remove(int index, int n) {
- Q_Q(QQmlObjectModel);
- for (int i = index; i < index + n; ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(-1);
- }
- children.erase(children.begin() + index, children.begin() + index + n);
- for (int i = index; i < children.count(); ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(i);
- }
- QQmlChangeSet changeSet;
- changeSet.remove(index, n);
- emit q->modelUpdated(changeSet, false);
- emit q->countChanged();
- emit q->childrenChanged();
- }
-
- void clear() {
- Q_Q(QQmlObjectModel);
- for (const Item &child : qAsConst(children))
- emit q->destroyingItem(child.item);
- remove(0, children.count());
- }
-
- int indexOf(QObject *item) const {
- for (int i = 0; i < children.count(); ++i)
- if (children.at(i).item == item)
- return i;
- return -1;
- }
-
- uint moveId;
- QList<Item> children;
-};
-
-
-/*!
- \qmltype ObjectModel
- \instantiates QQmlObjectModel
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Defines a set of items to be used as a model.
-
- An ObjectModel contains the visual items to be used in a view.
- When an ObjectModel is used in a view, the view does not require
- a delegate since the ObjectModel already contains the visual
- delegate (items).
-
- An item can determine its index within the
- model via the \l{ObjectModel::index}{index} attached property.
-
- The example below places three colored rectangles in a ListView.
- \code
- import QtQuick 2.0
- import QtQml.Models 2.1
-
- Rectangle {
- ObjectModel {
- id: itemModel
- Rectangle { height: 30; width: 80; color: "red" }
- Rectangle { height: 30; width: 80; color: "green" }
- Rectangle { height: 30; width: 80; color: "blue" }
- }
-
- ListView {
- anchors.fill: parent
- model: itemModel
- }
- }
- \endcode
-
- \image objectmodel.png
-
- \sa {Qt Quick Examples - Views}
-*/
-
-QQmlObjectModel::QQmlObjectModel(QObject *parent)
- : QQmlInstanceModel(*(new QQmlObjectModelPrivate), parent)
-{
-}
-
-/*!
- \qmlattachedproperty int QtQml.Models::ObjectModel::index
- This attached property holds the index of this delegate's item within the model.
-
- It is attached to each instance of the delegate.
-*/
-
-QQmlListProperty<QObject> QQmlObjectModel::children()
-{
- Q_D(QQmlObjectModel);
- return QQmlListProperty<QObject>(this,
- d,
- d->children_append,
- d->children_count,
- d->children_at,
- d->children_clear);
-}
-
-/*!
- \qmlproperty int QtQml.Models::ObjectModel::count
-
- The number of items in the model. This property is readonly.
-*/
-int QQmlObjectModel::count() const
-{
- Q_D(const QQmlObjectModel);
- return d->children.count();
-}
-
-bool QQmlObjectModel::isValid() const
-{
- return true;
-}
-
-QObject *QQmlObjectModel::object(int index, QQmlIncubator::IncubationMode)
-{
- Q_D(QQmlObjectModel);
- QQmlObjectModelPrivate::Item &item = d->children[index];
- item.addRef();
- if (item.ref == 1) {
- emit initItem(index, item.item);
- emit createdItem(index, item.item);
- }
- return item.item;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
-{
- Q_D(QQmlObjectModel);
- int idx = d->indexOf(item);
- if (idx >= 0) {
- if (!d->children[idx].deref())
- return QQmlInstanceModel::Referenced;
- }
- return nullptr;
-}
-
-QVariant QQmlObjectModel::variantValue(int index, const QString &role)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || index >= d->children.count())
- return QString();
- return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(role);
-}
-
-QQmlIncubator::Status QQmlObjectModel::incubationStatus(int)
-{
- return QQmlIncubator::Ready;
-}
-
-int QQmlObjectModel::indexOf(QObject *item, QObject *) const
-{
- Q_D(const QQmlObjectModel);
- return d->indexOf(item);
-}
-
-QQmlObjectModelAttached *QQmlObjectModel::qmlAttachedProperties(QObject *obj)
-{
- return QQmlObjectModelAttached::properties(obj);
-}
-
-/*!
- \qmlmethod object QtQml.Models::ObjectModel::get(int index)
- \since 5.6
-
- Returns the item at \a index in the model. This allows the item
- to be accessed or modified from JavaScript:
-
- \code
- Component.onCompleted: {
- objectModel.append(objectComponent.createObject())
- console.log(objectModel.get(0).objectName);
- objectModel.get(0).objectName = "first";
- }
- \endcode
-
- The \a index must be an element in the list.
-
- \sa append()
-*/
-QObject *QQmlObjectModel::get(int index) const
-{
- Q_D(const QQmlObjectModel);
- if (index < 0 || index >= d->children.count())
- return nullptr;
- return d->children.at(index).item;
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::append(object item)
- \since 5.6
-
- Appends a new item to the end of the model.
-
- \code
- objectModel.append(objectComponent.createObject())
- \endcode
-
- \sa insert(), remove()
-*/
-void QQmlObjectModel::append(QObject *object)
-{
- Q_D(QQmlObjectModel);
- d->insert(count(), object);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::insert(int index, object item)
- \since 5.6
-
- Inserts a new item to the model at position \a index.
-
- \code
- objectModel.insert(2, objectComponent.createObject())
- \endcode
-
- The \a index must be to an existing item in the list, or one past
- the end of the list (equivalent to append).
-
- \sa append(), remove()
-*/
-void QQmlObjectModel::insert(int index, QObject *object)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || index > count()) {
- qmlWarning(this) << tr("insert: index %1 out of range").arg(index);
- return;
- }
- d->insert(index, object);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::move(int from, int to, int n = 1)
- \since 5.6
-
- Moves \a n items \a from one position \a to another.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the model:
-
- \code
- objectModel.move(0, objectModel.count - 3, 3)
- \endcode
-
- \sa append()
-*/
-void QQmlObjectModel::move(int from, int to, int n)
-{
- Q_D(QQmlObjectModel);
- if (n <= 0 || from == to)
- return;
- if (from < 0 || to < 0 || from + n > count() || to + n > count()) {
- qmlWarning(this) << tr("move: out of range");
- return;
- }
- d->move(from, to, n);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::remove(int index, int n = 1)
- \since 5.6
-
- Removes the items at \a index from the model.
-
- \sa clear()
-*/
-void QQmlObjectModel::remove(int index, int n)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || n <= 0 || index + n > count()) {
- qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count());
- return;
- }
- d->remove(index, n);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::clear()
- \since 5.6
-
- Clears all items from the model.
-
- \sa append(), remove()
-*/
-void QQmlObjectModel::clear()
-{
- Q_D(QQmlObjectModel);
- d->clear();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlobjectmodel_p.cpp"
diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h
deleted file mode 100644
index 1284ba1780..0000000000
--- a/src/qml/types/qqmlobjectmodel_p.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANCEMODEL_P_H
-#define QQMLINSTANCEMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmlincubator_p.h>
-#include <QtQml/qqml.h>
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class QObject;
-class QQmlChangeSet;
-class QAbstractItemModel;
-
-class Q_QML_PRIVATE_EXPORT QQmlInstanceModel : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(int count READ count NOTIFY countChanged)
-
-public:
- virtual ~QQmlInstanceModel() {}
-
- enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
- Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
-
- virtual int count() const = 0;
- virtual bool isValid() const = 0;
- virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0;
- virtual ReleaseFlags release(QObject *object) = 0;
- virtual void cancel(int) {}
- QString stringValue(int index, const QString &role) { return variantValue(index, role).toString(); }
- virtual QVariant variantValue(int, const QString &) = 0;
- virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0;
- virtual QQmlIncubator::Status incubationStatus(int index) = 0;
-
- virtual int indexOf(QObject *object, QObject *objectContext) const = 0;
- virtual const QAbstractItemModel *abstractItemModel() const { return nullptr; }
-
-Q_SIGNALS:
- void countChanged();
- void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
- void createdItem(int index, QObject *object);
- void initItem(int index, QObject *object);
- void destroyingItem(QObject *object);
-
-protected:
- QQmlInstanceModel(QObjectPrivate &dd, QObject *parent = nullptr)
- : QObject(dd, parent) {}
-
-private:
- Q_DISABLE_COPY(QQmlInstanceModel)
-};
-
-class QQmlObjectModelAttached;
-class QQmlObjectModelPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQmlObjectModel)
-
- Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged DESIGNABLE false)
- Q_CLASSINFO("DefaultProperty", "children")
-
-public:
- QQmlObjectModel(QObject *parent=nullptr);
- ~QQmlObjectModel() {}
-
- int count() const override;
- bool isValid() const override;
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
- QVariant variantValue(int index, const QString &role) override;
- void setWatchedRoles(const QList<QByteArray> &) override {}
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *object, QObject *objectContext) const override;
-
- QQmlListProperty<QObject> children();
-
- static QQmlObjectModelAttached *qmlAttachedProperties(QObject *obj);
-
- Q_REVISION(3) Q_INVOKABLE QObject *get(int index) const;
- Q_REVISION(3) Q_INVOKABLE void append(QObject *object);
- Q_REVISION(3) Q_INVOKABLE void insert(int index, QObject *object);
- Q_REVISION(3) Q_INVOKABLE void move(int from, int to, int n = 1);
- Q_REVISION(3) Q_INVOKABLE void remove(int index, int n = 1);
-
-public Q_SLOTS:
- Q_REVISION(3) void clear();
-
-Q_SIGNALS:
- void childrenChanged();
-
-private:
- Q_DISABLE_COPY(QQmlObjectModel)
-};
-
-class QQmlObjectModelAttached : public QObject
-{
- Q_OBJECT
-
-public:
- QQmlObjectModelAttached(QObject *parent)
- : QObject(parent), m_index(-1) {}
- ~QQmlObjectModelAttached() {
- attachedProperties.remove(parent());
- }
-
- Q_PROPERTY(int index READ index NOTIFY indexChanged)
- int index() const { return m_index; }
- void setIndex(int idx) {
- if (m_index != idx) {
- m_index = idx;
- Q_EMIT indexChanged();
- }
- }
-
- static QQmlObjectModelAttached *properties(QObject *obj) {
- QQmlObjectModelAttached *rv = attachedProperties.value(obj);
- if (!rv) {
- rv = new QQmlObjectModelAttached(obj);
- attachedProperties.insert(obj, rv);
- }
- return rv;
- }
-
-Q_SIGNALS:
- void indexChanged();
-
-public:
- int m_index;
-
- static QHash<QObject*, QQmlObjectModelAttached*> attachedProperties;
-};
-
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlInstanceModel)
-QML_DECLARE_TYPE(QQmlObjectModel)
-QML_DECLARE_TYPEINFO(QQmlObjectModel, QML_HAS_ATTACHED_PROPERTIES)
-
-#endif // QQMLINSTANCEMODEL_P_H
diff --git a/src/qml/types/qqmltableinstancemodel.cpp b/src/qml/types/qqmltableinstancemodel.cpp
deleted file mode 100644
index 2170e2daec..0000000000
--- a/src/qml/types/qqmltableinstancemodel.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltableinstancemodel_p.h"
-#include "qqmldelegatecomponent_p.h"
-
-#include <QtCore/QTimer>
-
-#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
-#include <QtQml/private/qqmlcomponent_p.h>
-
-QT_BEGIN_NAMESPACE
-
-const char* kModelItemTag = "_tableinstancemodel_modelItem";
-
-bool QQmlTableInstanceModel::isDoneIncubating(QQmlDelegateModelItem *modelItem)
-{
- if (!modelItem->incubationTask)
- return true;
-
- const auto status = modelItem->incubationTask->status();
- return (status == QQmlIncubator::Ready) || (status == QQmlIncubator::Error);
-}
-
-void QQmlTableInstanceModel::deleteModelItemLater(QQmlDelegateModelItem *modelItem)
-{
- Q_ASSERT(modelItem);
-
- delete modelItem->object;
- modelItem->object = nullptr;
-
- if (modelItem->contextData) {
- modelItem->contextData->invalidate();
- Q_ASSERT(modelItem->contextData->refCount == 1);
- modelItem->contextData = nullptr;
- }
-
- modelItem->deleteLater();
-}
-
-QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent)
- : QQmlInstanceModel(*(new QObjectPrivate()), parent)
- , m_qmlContext(qmlContext)
- , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList()))
-{
-}
-
-void QQmlTableInstanceModel::useImportVersion(int minorVersion)
-{
- m_adaptorModel.useImportVersion(minorVersion);
-}
-
-QQmlTableInstanceModel::~QQmlTableInstanceModel()
-{
- for (const auto modelItem : m_modelItems) {
- // No item in m_modelItems should be referenced at this point. The view
- // should release all its items before it deletes this model. Only model items
- // that are still being incubated should be left for us to delete.
- Q_ASSERT(modelItem->objectRef == 0);
- Q_ASSERT(modelItem->incubationTask);
- // Check that we are not being deleted while we're
- // in the process of e.g emitting a created signal.
- Q_ASSERT(modelItem->scriptRef == 0);
-
- if (modelItem->object) {
- delete modelItem->object;
- modelItem->object = nullptr;
- modelItem->contextData->invalidate();
- modelItem->contextData = nullptr;
- }
- }
-
- deleteAllFinishedIncubationTasks();
- qDeleteAll(m_modelItems);
- drainReusableItemsPool(0);
-}
-
-QQmlComponent *QQmlTableInstanceModel::resolveDelegate(int index)
-{
- if (m_delegateChooser) {
- const int row = m_adaptorModel.rowAt(index);
- const int column = m_adaptorModel.columnAt(index);
- QQmlComponent *delegate = nullptr;
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, row, column);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- return delegate;
- }
-
- return m_delegate;
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
-{
- // Check if an item for the given index is already loaded and ready
- QQmlDelegateModelItem *modelItem = m_modelItems.value(index, nullptr);
- if (modelItem)
- return modelItem;
-
- QQmlComponent *delegate = resolveDelegate(index);
- if (!delegate)
- return nullptr;
-
- // Check if the pool contains an item that can be reused
- modelItem = takeFromReusableItemsPool(delegate);
- if (modelItem) {
- reuseItem(modelItem, index);
- m_modelItems.insert(index, modelItem);
- return modelItem;
- }
-
- // Create a new item from scratch
- modelItem = m_adaptorModel.createItem(m_metaType, index);
- if (modelItem) {
- modelItem->delegate = delegate;
- m_modelItems.insert(index, modelItem);
- return modelItem;
- }
-
- qWarning() << Q_FUNC_INFO << "failed creating a model item for index: " << index;
- return nullptr;
-}
-
-QObject *QQmlTableInstanceModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- Q_ASSERT(m_delegate);
- Q_ASSERT(index >= 0 && index < m_adaptorModel.count());
- Q_ASSERT(m_qmlContext && m_qmlContext->isValid());
-
- QQmlDelegateModelItem *modelItem = resolveModelItem(index);
- if (!modelItem)
- return nullptr;
-
- if (modelItem->object) {
- // The model item has already been incubated. So
- // just bump the ref-count and return it.
- modelItem->referenceObject();
- return modelItem->object;
- }
-
- // The object is not ready, and needs to be incubated
- incubateModelItem(modelItem, incubationMode);
- if (!isDoneIncubating(modelItem))
- return nullptr;
-
- // Incubation is done, so the task should be removed
- Q_ASSERT(!modelItem->incubationTask);
-
- if (!modelItem->object) {
- // The object was incubated synchronously (otherwise we would return above). But since
- // we have no object, the incubation must have failed. And when we have no object, there
- // should be no object references either. And there should also not be any internal script
- // refs at this point. So we delete the model item.
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- m_modelItems.remove(modelItem->index);
- delete modelItem;
- return nullptr;
- }
-
- // Incubation was completed sync and successful
- modelItem->referenceObject();
- return modelItem->object;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object, ReusableFlag reusable)
-{
- Q_ASSERT(object);
- auto modelItem = qvariant_cast<QQmlDelegateModelItem *>(object->property(kModelItemTag));
- Q_ASSERT(modelItem);
-
- if (!modelItem->releaseObject())
- return QQmlDelegateModel::Referenced;
-
- if (modelItem->isReferenced()) {
- // We still have an internal reference to this object, which means that we are told to release an
- // object while the createdItem signal for it is still on the stack. This can happen when objects
- // are e.g delivered async, and the user flicks back and forth quicker than the loading can catch
- // up with. The view might then find that the object is no longer visible and should be released.
- // We detect this case in incubatorStatusChanged(), and delete it there instead. But from the callers
- // point of view, it should consider it destroyed.
- return QQmlDelegateModel::Destroyed;
- }
-
- // The item is not referenced by anyone
- m_modelItems.remove(modelItem->index);
-
- if (reusable == Reusable) {
- insertIntoReusableItemsPool(modelItem);
- return QQmlInstanceModel::Referenced;
- }
-
- // The item is not reused or referenced by anyone, so just delete it
- modelItem->destroyObject();
- emit destroyingItem(object);
-
- delete modelItem;
- return QQmlInstanceModel::Destroyed;
-}
-
-void QQmlTableInstanceModel::cancel(int index)
-{
- auto modelItem = m_modelItems.value(index);
- Q_ASSERT(modelItem);
-
- // Since the view expects the item to be incubating, there should be
- // an incubation task. And since the incubation is not done, no-one
- // should yet have received, and therfore hold a reference to, the object.
- Q_ASSERT(modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
-
- m_modelItems.remove(index);
-
- if (modelItem->object)
- delete modelItem->object;
-
- // modelItem->incubationTask will be deleted from the modelItems destructor
- delete modelItem;
-}
-
-void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem)
-{
- // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release()
- // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released
- // item is no longer referenced, it will be added to the pool. Reusing of items can be specified
- // per item, in case certain items cannot be recycled.
- // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are
- // about to create a new item, we first check if the pool contains an item based on the same
- // delegate from before. If so, we take it out of the pool (instead of creating a new item), and
- // update all its context-, and attached properties.
- // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool()
- // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only
- // meant to rest there for a short while, ideally only from the time e.g a row is unloaded
- // on one side of the view, and until a new row is loaded on the opposite side. In-between
- // this time, the application will see the item as fully functional and 'alive' (just not
- // visible on screen). Since this time is supposed to be short, we don't take any action to
- // notify the application about it, since we don't want to trigger any bindings that can
- // disturb performance.
- // A recommended time for calling drainReusableItemsPool() is each time a view has finished
- // loading e.g a new row or column. If there are more items in the pool after that, it means
- // that the view most likely doesn't need them anytime soon. Those items should be destroyed to
- // not consume resources.
- // Depending on if a view is a list or a table, it can sometimes be performant to keep
- // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the
- // number of visible rows in a view is much larger than the number of visible columns.
- // In that case, if you flick out a row, and then flick in a column, you would throw away a lot
- // of items in the pool if completely draining it. The reason is that unloading a row places more
- // items in the pool than what ends up being recycled when loading a new column. And then, when you
- // next flick in a new row, you would need to load all those drained items again from scratch. For
- // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep
- // items in the pool for a bit longer, effectively keeping more items in circulation.
- // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which
- // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained.
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
-
- modelItem->poolTime = 0;
- m_reusableItemsPool.append(modelItem);
- emit itemPooled(modelItem->index, modelItem->object);
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate)
-{
- // Find the oldest item in the pool that was made from the same delegate as
- // the given argument, remove it from the pool, and return it.
- if (m_reusableItemsPool.isEmpty())
- return nullptr;
-
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
- if ((*it)->delegate != delegate)
- continue;
- auto modelItem = *it;
- m_reusableItemsPool.erase(it);
- return modelItem;
- }
-
- return nullptr;
-}
-
-void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime)
-{
- // Rather than releasing all pooled items upon a call to this function, each
- // item has a poolTime. The poolTime specifies for how many loading cycles an item
- // has been resting in the pool. And for each invocation of this function, poolTime
- // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
- // from the pool and released. This way, the view can tweak a bit for how long
- // items should stay in "circulation", even if they are not recycled right away.
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
- auto modelItem = *it;
- modelItem->poolTime++;
- if (modelItem->poolTime <= maxPoolTime) {
- ++it;
- } else {
- it = m_reusableItemsPool.erase(it);
- release(modelItem->object, NotReusable);
- }
- }
-}
-
-void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex)
-{
- // Update the context properties index, row and column on
- // the delegate item, and inform the application about it.
- const int newRow = m_adaptorModel.rowAt(newModelIndex);
- const int newColumn = m_adaptorModel.columnAt(newModelIndex);
- item->setModelIndex(newModelIndex, newRow, newColumn);
-
- // Notify the application that all 'dynamic'/role-based context data has
- // changed as well (their getter function will use the updated index).
- auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
- auto const updateAllRoles = QVector<int>();
- m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
-
- // Inform the view that the item is recycled. This will typically result
- // in the view updating its own attached delegate item properties.
- emit itemReused(newModelIndex, item->object);
-}
-
-void QQmlTableInstanceModel::incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode)
-{
- // Guard the model item temporarily so that it's not deleted from
- // incubatorStatusChanged(), in case the incubation is done synchronously.
- modelItem->scriptRef++;
-
- if (modelItem->incubationTask) {
- // We're already incubating the model item from a previous request. If the previous call requested
- // the item async, but the current request needs it sync, we need to force-complete the incubation.
- const bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
- if (sync && modelItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous)
- modelItem->incubationTask->forceCompletion();
- } else {
- modelItem->incubationTask = new QQmlTableInstanceModelIncubationTask(this, modelItem, incubationMode);
-
- QQmlContextData *ctxt = new QQmlContextData;
- QQmlContext *creationContext = modelItem->delegate->creationContext();
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_qmlContext.data()));
- ctxt->contextObject = modelItem;
- modelItem->contextData = ctxt;
-
- QQmlComponentPrivate::get(modelItem->delegate)->incubateObject(
- modelItem->incubationTask,
- modelItem->delegate,
- m_qmlContext->engine(),
- ctxt,
- QQmlContextData::get(m_qmlContext));
- }
-
- // Remove the temporary guard
- modelItem->scriptRef--;
-}
-
-void QQmlTableInstanceModel::incubatorStatusChanged(QQmlTableInstanceModelIncubationTask *incubationTask, QQmlIncubator::Status status)
-{
- QQmlDelegateModelItem *modelItem = incubationTask->modelItemToIncubate;
- Q_ASSERT(modelItem->incubationTask);
-
- modelItem->incubationTask = nullptr;
- incubationTask->modelItemToIncubate = nullptr;
-
- if (status == QQmlIncubator::Ready) {
- // Tag the incubated object with the model item for easy retrieval upon release etc.
- modelItem->object->setProperty(kModelItemTag, QVariant::fromValue(modelItem));
-
- // Emit that the item has been created. What normally happens next is that the view
- // upon receiving the signal asks for the model item once more. And since the item is
- // now in the map, it will be returned directly.
- Q_ASSERT(modelItem->object);
- modelItem->scriptRef++;
- emit createdItem(modelItem->index, modelItem->object);
- modelItem->scriptRef--;
- } else if (status == QQmlIncubator::Error) {
- qWarning() << "Error incubating delegate:" << incubationTask->errors();
- }
-
- if (!modelItem->isReferenced() && !modelItem->isObjectReferenced()) {
- // We have no internal reference to the model item, and the view has no
- // reference to the incubated object. So just delete the model item.
- // Note that being here means that the object was incubated _async_
- // (otherwise modelItem->isReferenced() would be true).
- m_modelItems.remove(modelItem->index);
-
- if (modelItem->object) {
- modelItem->scriptRef++;
- emit destroyingItem(modelItem->object);
- modelItem->scriptRef--;
- Q_ASSERT(!modelItem->isReferenced());
- }
-
- deleteModelItemLater(modelItem);
- }
-
- deleteIncubationTaskLater(incubationTask);
-}
-
-QQmlIncubator::Status QQmlTableInstanceModel::incubationStatus(int index) {
- const auto modelItem = m_modelItems.value(index, nullptr);
- if (!modelItem)
- return QQmlIncubator::Null;
-
- if (modelItem->incubationTask)
- return modelItem->incubationTask->status();
-
- // Since we clear the incubation task when we're done
- // incubating, it means that the status is Ready.
- return QQmlIncubator::Ready;
-}
-
-void QQmlTableInstanceModel::deleteIncubationTaskLater(QQmlIncubator *incubationTask)
-{
- // We often need to post-delete incubation tasks, since we cannot
- // delete them while we're in the middle of an incubation change callback.
- Q_ASSERT(!m_finishedIncubationTasks.contains(incubationTask));
- m_finishedIncubationTasks.append(incubationTask);
- if (m_finishedIncubationTasks.count() == 1)
- QTimer::singleShot(1, this, &QQmlTableInstanceModel::deleteAllFinishedIncubationTasks);
-}
-
-void QQmlTableInstanceModel::deleteAllFinishedIncubationTasks()
-{
- qDeleteAll(m_finishedIncubationTasks);
- m_finishedIncubationTasks.clear();
-}
-
-QVariant QQmlTableInstanceModel::model() const
-{
- return m_adaptorModel.model();
-}
-
-void QQmlTableInstanceModel::setModel(const QVariant &model)
-{
- // Pooled items are still accessible/alive for the application, and
- // needs to stay in sync with the model. So we need to drain the pool
- // completely when the model changes.
- drainReusableItemsPool(0);
- if (auto const aim = abstractItemModel())
- disconnect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
- m_adaptorModel.setModel(model, this, m_qmlContext->engine());
- if (auto const aim = abstractItemModel())
- connect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
-}
-
-void QQmlTableInstanceModel::dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
-{
- // This function is called when model data has changed. In that case, we tell the adaptor model
- // to go through all the items we have created, find the ones that are affected, and notify that
- // their model data has changed. This will in turn update QML bindings inside the delegate items.
- int numberOfRowsChanged = end.row() - begin.row() + 1;
- int numberOfColumnsChanged = end.column() - begin.column() + 1;
-
- for (int column = 0; column < numberOfColumnsChanged; ++column) {
- const int columnIndex = begin.column() + column;
- const int rowIndex = begin.row() + (columnIndex * rows());
- m_adaptorModel.notify(m_modelItems.values(), rowIndex, numberOfRowsChanged, roles);
- }
-}
-
-QQmlComponent *QQmlTableInstanceModel::delegate() const
-{
- return m_delegate;
-}
-
-void QQmlTableInstanceModel::setDelegate(QQmlComponent *delegate)
-{
- if (m_delegate == delegate)
- return;
-
- m_delegateChooser = nullptr;
- if (delegate) {
- QQmlAbstractDelegateComponent *adc =
- qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc)
- m_delegateChooser = adc;
- }
-
- m_delegate = delegate;
-}
-
-const QAbstractItemModel *QQmlTableInstanceModel::abstractItemModel() const
-{
- return m_adaptorModel.adaptsAim() ? m_adaptorModel.aim() : nullptr;
-}
-
-// --------------------------------------------------------
-
-void QQmlTableInstanceModelIncubationTask::setInitialState(QObject *object)
-{
- modelItemToIncubate->object = object;
- emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
-}
-
-void QQmlTableInstanceModelIncubationTask::statusChanged(QQmlIncubator::Status status)
-{
- if (!QQmlTableInstanceModel::isDoneIncubating(modelItemToIncubate))
- return;
-
- // We require the view to cancel any ongoing load
- // requests before the tableInstanceModel is destructed.
- Q_ASSERT(tableInstanceModel);
-
- tableInstanceModel->incubatorStatusChanged(this, status);
-}
-
-#include "moc_qqmltableinstancemodel_p.cpp"
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/types/qqmltableinstancemodel_p.h b/src/qml/types/qqmltableinstancemodel_p.h
deleted file mode 100644
index 39ec66d136..0000000000
--- a/src/qml/types/qqmltableinstancemodel_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEINSTANCEMODEL_P_H
-#define QQMLTABLEINSTANCEMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlTableInstanceModel;
-class QQmlAbstractDelegateComponent;
-
-class QQmlTableInstanceModelIncubationTask : public QQDMIncubationTask
-{
-public:
- QQmlTableInstanceModelIncubationTask(
- QQmlTableInstanceModel *tableInstanceModel
- , QQmlDelegateModelItem* modelItemToIncubate
- , IncubationMode mode)
- : QQDMIncubationTask(nullptr, mode)
- , modelItemToIncubate(modelItemToIncubate)
- , tableInstanceModel(tableInstanceModel) {
- clear();
- }
-
- void statusChanged(Status status) override;
- void setInitialState(QObject *object) override;
-
- QQmlDelegateModelItem *modelItemToIncubate = nullptr;
- QQmlTableInstanceModel *tableInstanceModel = nullptr;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
-{
- Q_OBJECT
-
-public:
-
- enum ReusableFlag {
- NotReusable,
- Reusable
- };
-
- QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent = nullptr);
- ~QQmlTableInstanceModel() override;
-
- void useImportVersion(int minorVersion);
-
- int count() const override { return m_adaptorModel.count(); }
- int rows() const { return m_adaptorModel.rowCount(); }
- int columns() const { return m_adaptorModel.columnCount(); }
-
- bool isValid() const override { return true; }
-
- QVariant model() const;
- void setModel(const QVariant &model);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *);
-
- const QAbstractItemModel *abstractItemModel() const override;
-
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override { return release(object, NotReusable); }
- ReleaseFlags release(QObject *object, ReusableFlag reusable);
- void cancel(int) override;
-
- void insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem);
- QQmlDelegateModelItem *takeFromReusableItemsPool(const QQmlComponent *delegate);
- void drainReusableItemsPool(int maxPoolTime);
- int poolSize() { return m_reusableItemsPool.size(); }
- void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
-
- QQmlIncubator::Status incubationStatus(int index) override;
-
- QVariant variantValue(int, const QString &) override { Q_UNREACHABLE(); return QVariant(); }
- void setWatchedRoles(const QList<QByteArray> &) override { Q_UNREACHABLE(); }
- int indexOf(QObject *, QObject *) const override { Q_UNREACHABLE(); return 0; }
-
-Q_SIGNALS:
- void itemPooled(int index, QObject *object);
- void itemReused(int index, QObject *object);
-
-private:
- QQmlComponent *resolveDelegate(int index);
-
- QQmlAdaptorModel m_adaptorModel;
- QQmlAbstractDelegateComponent *m_delegateChooser = nullptr;
- QQmlComponent *m_delegate = nullptr;
- QPointer<QQmlContext> m_qmlContext;
- QQmlDelegateModelItemMetaType *m_metaType;
-
- QHash<int, QQmlDelegateModelItem *> m_modelItems;
- QList<QQmlDelegateModelItem *> m_reusableItemsPool;
- QList<QQmlIncubator *> m_finishedIncubationTasks;
-
- void incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode);
- void incubatorStatusChanged(QQmlTableInstanceModelIncubationTask *dmIncubationTask, QQmlIncubator::Status status);
- void deleteIncubationTaskLater(QQmlIncubator *incubationTask);
- void deleteAllFinishedIncubationTasks();
- QQmlDelegateModelItem *resolveModelItem(int index);
-
- void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles);
-
- static bool isDoneIncubating(QQmlDelegateModelItem *modelItem);
- static void deleteModelItemLater(QQmlDelegateModelItem *modelItem);
-
- friend class QQmlTableInstanceModelIncubationTask;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTABLEINSTANCEMODEL_P_H
diff --git a/src/qml/types/qqmltablemodel.cpp b/src/qml/types/qqmltablemodel.cpp
deleted file mode 100644
index 4a96e7a46b..0000000000
--- a/src/qml/types/qqmltablemodel.cpp
+++ /dev/null
@@ -1,1059 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltablemodel_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtQml/qqmlinfo.h>
-#include <QtQml/qqmlengine.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTableModel, "qt.qml.tablemodel")
-
-/*!
- \qmltype TableModel
- \instantiates QQmlTableModel
- \inqmlmodule Qt.labs.qmlmodels
- \brief Encapsulates a simple table model.
- \since 5.14
-
- The TableModel type stores JavaScript/JSON objects as data for a table
- model that can be used with \l TableView. It is intended to support
- very simple models without requiring the creation of a custom
- QAbstractTableModel subclass in C++.
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml file
-
- The model's initial row data is set with either the \l rows property or by
- calling \l appendRow(). Each column in the model is specified by declaring
- a \l TableModelColumn instance, where the order of each instance determines
- its column index. Once the model's \l Component.completed() signal has been
- emitted, the columns and roles will have been established and are then
- fixed for the lifetime of the model.
-
- To access a specific row, the \l getRow() function can be used.
- It's also possible to access the model's JavaScript data
- directly via the \l rows property, but it is not possible to
- modify the model data this way.
-
- To add new rows, use \l appendRow() and \l insertRow(). To modify
- existing rows, use \l setRow(), \l moveRow(), \l removeRow(), and
- \l clear().
-
- It is also possible to modify the model's data via the delegate,
- as shown in the example above:
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml delegate
-
- If the type of the data at the modified role does not match the type of the
- data that is set, it will be automatically converted via
- \l {QVariant::canConvert()}{QVariant}.
-
- \section1 Supported Row Data Structures
-
- TableModel is designed to work with JavaScript/JSON data, where each row
- is a simple key-pair object:
-
- \code
- {
- // Each property is one cell/column.
- checked: false,
- amount: 1,
- fruitType: "Apple",
- fruitName: "Granny Smith",
- fruitPrice: 1.50
- },
- // ...
- \endcode
-
- As model manipulation in Qt is done via row and column indices,
- and because object keys are unordered, each column must be specified via
- TableModelColumn. This allows mapping Qt's built-in roles to any property
- in each row object.
-
- Complex row structures are supported, but with limited functionality.
- As TableModel has no way of knowing how each row is structured,
- it cannot manipulate it. As a consequence of this, the copy of the
- model data that TableModel has stored in \l rows is not kept in sync
- with the source data that was set in QML. For these reasons, TableModel
- relies on the user to handle simple data manipulation.
-
- For example, suppose you wanted to have several roles per column. One way
- of doing this is to use a data source where each row is an array and each
- cell is an object. To use this data source with TableModel, define a
- getter and setter:
-
- \code
- TableModel {
- TableModelColumn {
- display: function(modelIndex) { return rows[modelIndex.row][0].checked }
- setDisplay: function(modelIndex, cellData) { rows[modelIndex.row][0].checked = cellData }
- }
- // ...
-
- rows: [
- [
- { checked: false, checkable: true },
- { amount: 1 },
- { fruitType: "Apple" },
- { fruitName: "Granny Smith" },
- { fruitPrice: 1.50 }
- ]
- // ...
- ]
- }
- \endcode
-
- The row above is one example of a complex row.
-
- \note Row manipulation functions such as \l appendRow(), \l removeRow(),
- etc. are not supported when using complex rows.
-
- \section1 Using DelegateChooser with TableModel
-
- For most real world use cases, it is recommended to use DelegateChooser
- as the delegate of a TableView that uses TableModel. This allows you to
- use specific roles in the relevant delegates. For example, the snippet
- above can be rewritten to use DelegateChooser like so:
-
- \snippet qml/tablemodel/fruit-example-delegatechooser.qml file
-
- The most specific delegates are declared first: the columns at index \c 0
- and \c 1 have \c bool and \c integer data types, so they use a
- \l [QtQuickControls2]{CheckBox} and \l [QtQuickControls2]{SpinBox},
- respectively. The remaining columns can simply use a
- \l [QtQuickControls2]{TextField}, and so that delegate is declared
- last as a fallback.
-
- \sa TableModelColumn, TableView, QAbstractTableModel
-*/
-
-QQmlTableModel::QQmlTableModel(QObject *parent)
- : QAbstractTableModel(parent)
-{
-}
-
-QQmlTableModel::~QQmlTableModel()
-{
-}
-
-/*!
- \qmlproperty object TableModel::rows
-
- This property holds the model data in the form of an array of rows:
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml rows
-
- \sa getRow(), setRow(), moveRow(), appendRow(), insertRow(), clear(), rowCount, columnCount
-*/
-QVariant QQmlTableModel::rows() const
-{
- return mRows;
-}
-
-void QQmlTableModel::setRows(const QVariant &rows)
-{
- if (rows.userType() != qMetaTypeId<QJSValue>()) {
- qmlWarning(this) << "setRows(): \"rows\" must be an array; actual type is " << rows.typeName();
- return;
- }
-
- const QJSValue rowsAsJSValue = rows.value<QJSValue>();
- const QVariantList rowsAsVariantList = rowsAsJSValue.toVariant().toList();
- if (rowsAsVariantList == mRows) {
- // No change.
- return;
- }
-
- if (!componentCompleted) {
- // Store the rows until we can call doSetRows() after component completion.
- mRows = rowsAsVariantList;
- return;
- }
-
- doSetRows(rowsAsVariantList);
-}
-
-void QQmlTableModel::doSetRows(const QVariantList &rowsAsVariantList)
-{
- Q_ASSERT(componentCompleted);
-
- // By now, all TableModelColumns should have been set.
- if (mColumns.isEmpty()) {
- qmlWarning(this) << "No TableModelColumns were set; model will be empty";
- return;
- }
-
- const bool firstTimeValidRowsHaveBeenSet = mColumnMetadata.isEmpty();
- if (!firstTimeValidRowsHaveBeenSet) {
- // This is not the first time rows have been set; validate each one.
- for (int rowIndex = 0; rowIndex < rowsAsVariantList.size(); ++rowIndex) {
- // validateNewRow() expects a QVariant wrapping a QJSValue, so to
- // simplify the code, just create one here.
- const QVariant row = QVariant::fromValue(rowsAsVariantList.at(rowIndex));
- if (!validateNewRow("setRows()", row, rowIndex, SetRowsOperation))
- return;
- }
- }
-
- const int oldRowCount = mRowCount;
- const int oldColumnCount = mColumnCount;
-
- beginResetModel();
-
- // We don't clear the column or role data, because a TableModel should not be reused in that way.
- // Once it has valid data, its columns and roles are fixed.
- mRows = rowsAsVariantList;
- mRowCount = mRows.size();
-
- // Gather metadata the first time rows is set.
- if (firstTimeValidRowsHaveBeenSet && !mRows.isEmpty())
- fetchColumnMetadata();
-
- endResetModel();
-
- emit rowsChanged();
-
- if (mRowCount != oldRowCount)
- emit rowCountChanged();
- if (mColumnCount != oldColumnCount)
- emit columnCountChanged();
-}
-
-QQmlTableModel::ColumnRoleMetadata QQmlTableModel::fetchColumnRoleData(const QString &roleNameKey,
- QQmlTableModelColumn *tableModelColumn, int columnIndex) const
-{
- const QVariant firstRow = mRows.first();
- ColumnRoleMetadata roleData;
-
- QJSValue columnRoleGetter = tableModelColumn->getterAtRole(roleNameKey);
- if (columnRoleGetter.isUndefined()) {
- // This role is not defined, which is fine; just skip it.
- return roleData;
- }
-
- if (columnRoleGetter.isString()) {
- // The role is set as a string, so we assume the row is a simple object.
- if (firstRow.type() != QVariant::Map) {
- qmlWarning(this).quote() << "expected row for role "
- << roleNameKey << " of TableModelColumn at index "
- << columnIndex << " to be a simple object, but it's "
- << firstRow.typeName() << " instead: " << firstRow;
- return roleData;
- }
- const QVariantMap firstRowAsMap = firstRow.toMap();
- const QString rolePropertyName = columnRoleGetter.toString();
- const QVariant roleProperty = firstRowAsMap.value(rolePropertyName);
-
- roleData.isStringRole = true;
- roleData.name = rolePropertyName;
- roleData.type = roleProperty.type();
- roleData.typeName = QString::fromLatin1(roleProperty.typeName());
- } else if (columnRoleGetter.isCallable()) {
- // The role is provided via a function, which means the row is complex and
- // the user needs to provide the data for it.
- const auto modelIndex = index(0, columnIndex);
- const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(modelIndex);
- const QVariant cellData = columnRoleGetter.call(args).toVariant();
-
- // We don't know the property name since it's provided through the function.
- // roleData.name = ???
- roleData.isStringRole = false;
- roleData.type = cellData.type();
- roleData.typeName = QString::fromLatin1(cellData.typeName());
- } else {
- // Invalid role.
- qmlWarning(this) << "TableModelColumn role for column at index "
- << columnIndex << " must be either a string or a function; actual type is: "
- << columnRoleGetter.toString();
- }
-
- return roleData;
-}
-
-void QQmlTableModel::fetchColumnMetadata()
-{
- qCDebug(lcTableModel) << "gathering metadata for" << mColumnCount << "columns from first row:";
-
- static const auto supportedRoleNames = QQmlTableModelColumn::supportedRoleNames();
-
- // Since we support different data structures at the row level, we require that there
- // is a TableModelColumn for each column.
- // Collect and cache metadata for each column. This makes data lookup faster.
- for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
- QQmlTableModelColumn *column = mColumns.at(columnIndex);
- qCDebug(lcTableModel).nospace() << "- column " << columnIndex << ":";
-
- ColumnMetadata metaData;
- const auto builtInRoleKeys = supportedRoleNames.keys();
- for (const int builtInRoleKey : builtInRoleKeys) {
- const QString builtInRoleName = supportedRoleNames.value(builtInRoleKey);
- ColumnRoleMetadata roleData = fetchColumnRoleData(builtInRoleName, column, columnIndex);
- if (roleData.type == QVariant::Invalid) {
- // This built-in role was not specified in this column.
- continue;
- }
-
- qCDebug(lcTableModel).nospace() << " - added metadata for built-in role "
- << builtInRoleName << " at column index " << columnIndex
- << ": name=" << roleData.name << " typeName=" << roleData.typeName
- << " type=" << roleData.type;
-
- // This column now supports this specific built-in role.
- metaData.roles.insert(builtInRoleName, roleData);
- // Add it if it doesn't already exist.
- mRoleNames[builtInRoleKey] = builtInRoleName.toLatin1();
- }
- mColumnMetadata.insert(columnIndex, metaData);
- }
-}
-
-/*!
- \qmlmethod TableModel::appendRow(object row)
-
- Adds a new row to the end of the model, with the
- values (cells) in \a row.
-
- \code
- model.appendRow({
- checkable: true,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- \sa insertRow(), setRow(), removeRow()
-*/
-void QQmlTableModel::appendRow(const QVariant &row)
-{
- if (!validateNewRow("appendRow()", row, -1, AppendOperation))
- return;
-
- doInsert(mRowCount, row);
-}
-
-/*!
- \qmlmethod TableModel::clear()
-
- Removes all rows from the model.
-
- \sa removeRow()
-*/
-void QQmlTableModel::clear()
-{
- QQmlEngine *engine = qmlEngine(this);
- Q_ASSERT(engine);
- setRows(QVariant::fromValue(engine->newArray()));
-}
-
-/*!
- \qmlmethod object TableModel::getRow(int rowIndex)
-
- Returns the row at \a rowIndex in the model.
-
- Note that this equivalent to accessing the row directly
- through the \l rows property:
-
- \code
- Component.onCompleted: {
- // These two lines are equivalent.
- console.log(model.getRow(0).display);
- console.log(model.rows[0].fruitName);
- }
- \endcode
-
- \note the returned object cannot be used to modify the contents of the
- model; use setRow() instead.
-
- \sa setRow(), appendRow(), insertRow(), removeRow(), moveRow()
-*/
-QVariant QQmlTableModel::getRow(int rowIndex)
-{
- if (!validateRowIndex("getRow()", "rowIndex", rowIndex))
- return QVariant();
-
- return mRows.at(rowIndex);
-}
-
-/*!
- \qmlmethod TableModel::insertRow(int rowIndex, object row)
-
- Adds a new row to the list model at position \a rowIndex, with the
- values (cells) in \a row.
-
- \code
- model.insertRow(2, {
- checkable: true, checked: false,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- The \a rowIndex must be to an existing item in the list, or one past
- the end of the list (equivalent to \l appendRow()).
-
- \sa appendRow(), setRow(), removeRow(), rowCount
-*/
-void QQmlTableModel::insertRow(int rowIndex, const QVariant &row)
-{
- if (!validateNewRow("insertRow()", row, rowIndex))
- return;
-
- doInsert(rowIndex, row);
-}
-
-void QQmlTableModel::doInsert(int rowIndex, const QVariant &row)
-{
- beginInsertRows(QModelIndex(), rowIndex, rowIndex);
-
- // Adding rowAsVariant.toList() will add each invidual variant in the list,
- // which is definitely not what we want.
- const QVariant rowAsVariant = row.value<QJSValue>().toVariant();
- mRows.insert(rowIndex, rowAsVariant);
- ++mRowCount;
-
- qCDebug(lcTableModel).nospace() << "inserted the following row to the model at index "
- << rowIndex << ":\n" << rowAsVariant.toMap();
-
- // Gather metadata the first time a row is added.
- if (mColumnMetadata.isEmpty())
- fetchColumnMetadata();
-
- endInsertRows();
- emit rowCountChanged();
-}
-
-void QQmlTableModel::classBegin()
-{
-}
-
-void QQmlTableModel::componentComplete()
-{
- componentCompleted = true;
-
- mColumnCount = mColumns.size();
- if (mColumnCount > 0)
- emit columnCountChanged();
-
- doSetRows(mRows);
-}
-
-/*!
- \qmlmethod TableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
-
- Moves \a rows from the index at \a fromRowIndex to the index at
- \a toRowIndex.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the list:
-
- \code
- model.moveRow(0, model.rowCount - 3, 3)
- \endcode
-
- \sa appendRow(), insertRow(), removeRow(), rowCount
-*/
-void QQmlTableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
-{
- if (fromRowIndex == toRowIndex) {
- qmlWarning(this) << "moveRow(): \"fromRowIndex\" cannot be equal to \"toRowIndex\"";
- return;
- }
-
- if (rows <= 0) {
- qmlWarning(this) << "moveRow(): \"rows\" is less than or equal to 0";
- return;
- }
-
- if (!validateRowIndex("moveRow()", "fromRowIndex", fromRowIndex))
- return;
-
- if (!validateRowIndex("moveRow()", "toRowIndex", toRowIndex))
- return;
-
- if (fromRowIndex + rows > mRowCount) {
- qmlWarning(this) << "moveRow(): \"fromRowIndex\" (" << fromRowIndex
- << ") + \"rows\" (" << rows << ") = " << (fromRowIndex + rows)
- << ", which is greater than rowCount() of " << mRowCount;
- return;
- }
-
- if (toRowIndex + rows > mRowCount) {
- qmlWarning(this) << "moveRow(): \"toRowIndex\" (" << toRowIndex
- << ") + \"rows\" (" << rows << ") = " << (toRowIndex + rows)
- << ", which is greater than rowCount() of " << mRowCount;
- return;
- }
-
- qCDebug(lcTableModel).nospace() << "moving " << rows
- << " row(s) from index " << fromRowIndex
- << " to index " << toRowIndex;
-
- // Based on the same call in QQmlListModel::moveRow().
- beginMoveRows(QModelIndex(), fromRowIndex, fromRowIndex + rows - 1, QModelIndex(),
- toRowIndex > fromRowIndex ? toRowIndex + rows : toRowIndex);
-
- // Based on ListModel::moveRow().
- if (fromRowIndex > toRowIndex) {
- // Only move forwards - flip if moving backwards.
- const int from = fromRowIndex;
- const int to = toRowIndex;
- fromRowIndex = to;
- toRowIndex = to + rows;
- rows = from - to;
- }
-
- QVector<QVariant> store;
- store.reserve(rows);
- for (int i = 0; i < (toRowIndex - fromRowIndex); ++i)
- store.append(mRows.at(fromRowIndex + rows + i));
- for (int i = 0; i < rows; ++i)
- store.append(mRows.at(fromRowIndex + i));
- for (int i = 0; i < store.size(); ++i)
- mRows[fromRowIndex + i] = store[i];
-
- qCDebug(lcTableModel).nospace() << "after moving, rows are:\n" << mRows;
-
- endMoveRows();
-}
-
-/*!
- \qmlmethod TableModel::removeRow(int rowIndex, int rows = 1)
-
- Removes the row at \a rowIndex from the model.
-
- \sa clear(), rowCount
-*/
-void QQmlTableModel::removeRow(int rowIndex, int rows)
-{
- if (!validateRowIndex("removeRow()", "rowIndex", rowIndex))
- return;
-
- if (rows <= 0) {
- qmlWarning(this) << "removeRow(): \"rows\" is less than or equal to zero";
- return;
- }
-
- if (rowIndex + rows - 1 >= mRowCount) {
- qmlWarning(this) << "removeRow(): \"rows\" " << rows
- << " exceeds available rowCount() of " << mRowCount
- << " when removing from \"rowIndex\" " << rowIndex;
- return;
- }
-
- beginRemoveRows(QModelIndex(), rowIndex, rowIndex + rows - 1);
-
- auto firstIterator = mRows.begin() + rowIndex;
- // The "last" argument to erase() is exclusive, so we go one past the last item.
- auto lastIterator = firstIterator + rows;
- mRows.erase(firstIterator, lastIterator);
- mRowCount -= rows;
-
- endRemoveRows();
- emit rowCountChanged();
-
- qCDebug(lcTableModel).nospace() << "removed " << rows
- << " items from the model, starting at index " << rowIndex;
-}
-
-/*!
- \qmlmethod TableModel::setRow(int rowIndex, object row)
-
- Changes the row at \a rowIndex in the model with \a row.
-
- All columns/cells must be present in \c row, and in the correct order.
-
- \code
- model.setRow(0, {
- checkable: true,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- If \a rowIndex is equal to \c rowCount(), then a new row is appended to the
- model. Otherwise, \a rowIndex must point to an existing row in the model.
-
- \sa appendRow(), insertRow(), rowCount
-*/
-void QQmlTableModel::setRow(int rowIndex, const QVariant &row)
-{
- if (!validateNewRow("setRow()", row, rowIndex))
- return;
-
- if (rowIndex != mRowCount) {
- // Setting an existing row.
- mRows[rowIndex] = row;
-
- // For now we just assume the whole row changed, as it's simpler.
- const QModelIndex topLeftModelIndex(createIndex(rowIndex, 0));
- const QModelIndex bottomRightModelIndex(createIndex(rowIndex, mColumnCount - 1));
- emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
- } else {
- // Appending a row.
- doInsert(rowIndex, row);
- }
-}
-
-QQmlListProperty<QQmlTableModelColumn> QQmlTableModel::columns()
-{
- return QQmlListProperty<QQmlTableModelColumn>(this, nullptr,
- &QQmlTableModel::columns_append,
- &QQmlTableModel::columns_count,
- &QQmlTableModel::columns_at,
- &QQmlTableModel::columns_clear);
-}
-
-void QQmlTableModel::columns_append(QQmlListProperty<QQmlTableModelColumn> *property,
- QQmlTableModelColumn *value)
-{
- QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- QQmlTableModelColumn *column = qobject_cast<QQmlTableModelColumn*>(value);
- if (column)
- model->mColumns.append(column);
-}
-
-int QQmlTableModel::columns_count(QQmlListProperty<QQmlTableModelColumn> *property)
-{
- const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.count();
-}
-
-QQmlTableModelColumn *QQmlTableModel::columns_at(QQmlListProperty<QQmlTableModelColumn> *property, int index)
-{
- const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.at(index);
-}
-
-void QQmlTableModel::columns_clear(QQmlListProperty<QQmlTableModelColumn> *property)
-{
- QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.clear();
-}
-
-/*!
- \qmlmethod QModelIndex TableModel::index(int row, int column)
-
- Returns a \l QModelIndex object referencing the given \a row and \a column,
- which can be passed to the data() function to get the data from that cell,
- or to setData() to edit the contents of that cell.
-
- \code
- import QtQml 2.14
- import Qt.labs.qmlmodels 1.0
-
- TableModel {
- id: model
-
- TableModelColumn { display: "fruitType" }
- TableModelColumn { display: "fruitPrice" }
-
- rows: [
- { fruitType: "Apple", fruitPrice: 1.50 },
- { fruitType: "Orange", fruitPrice: 2.50 }
- ]
-
- Component.onCompleted: {
- for (var r = 0; r < model.rowCount; ++r) {
- console.log("An " + model.data(model.index(r, 0)).display +
- " costs " + model.data(model.index(r, 1)).display.toFixed(2))
- }
- }
- }
- \endcode
-
- \sa {QModelIndex and related Classes in QML}, data()
-*/
-// Note: we don't document the parent argument, because you never need it, because
-// cells in a TableModel don't have parents. But it is there because this function is an override.
-QModelIndex QQmlTableModel::index(int row, int column, const QModelIndex &parent) const
-{
- return row >= 0 && row < rowCount() && column >= 0 && column < columnCount() && !parent.isValid()
- ? createIndex(row, column)
- : QModelIndex();
-}
-
-/*!
- \qmlproperty int TableModel::rowCount
- \readonly
-
- This read-only property holds the number of rows in the model.
-
- This value changes whenever rows are added or removed from the model.
-*/
-int QQmlTableModel::rowCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return mRowCount;
-}
-
-/*!
- \qmlproperty int TableModel::columnCount
- \readonly
-
- This read-only property holds the number of columns in the model.
-
- The number of columns is fixed for the lifetime of the model
- after the \l rows property is set or \l appendRow() is called for the first
- time.
-*/
-int QQmlTableModel::columnCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return mColumnCount;
-}
-
-/*!
- \qmlmethod variant TableModel::data(QModelIndex index, string role)
-
- Returns the data from the table cell at the given \a index belonging to the
- given \a role.
-
- \sa index()
-*/
-QVariant QQmlTableModel::data(const QModelIndex &index, const QString &role) const
-{
- const int iRole = mRoleNames.key(role.toUtf8(), -1);
- if (iRole >= 0)
- return data(index, iRole);
- return QVariant();
-}
-
-QVariant QQmlTableModel::data(const QModelIndex &index, int role) const
-{
- const int row = index.row();
- if (row < 0 || row >= rowCount())
- return QVariant();
-
- const int column = index.column();
- if (column < 0 || column >= columnCount())
- return QVariant();
-
- const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
- const QString roleName = QString::fromUtf8(mRoleNames.value(role));
- if (!columnMetadata.roles.contains(roleName)) {
- qmlWarning(this) << "setData(): no role named " << roleName
- << " at column index " << column << ". The available roles for that column are: "
- << columnMetadata.roles.keys();
- return QVariant();
- }
-
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- if (roleData.isStringRole) {
- // We know the data structure, so we can get the data for the user.
- const QVariantMap rowData = mRows.at(row).toMap();
- const QString propertyName = columnMetadata.roles.value(roleName).name;
- const QVariant value = rowData.value(propertyName);
- return value;
- }
-
- // We don't know the data structure, so the user has to modify their data themselves.
- // First, find the getter for this column and role.
- QJSValue getter = mColumns.at(column)->getterAtRole(roleName);
-
- // Then, call it and return what it returned.
- const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(index);
- return getter.call(args).toVariant();
-}
-
-/*!
- \qmlmethod bool TableModel::setData(QModelIndex index, string role, variant value)
-
- Inserts or updates the data field named by \a role in the table cell at the
- given \a index with \a value. Returns true if sucessful, false if not.
-
- \sa index()
-*/
-bool QQmlTableModel::setData(const QModelIndex &index, const QString &role, const QVariant &value)
-{
- const int intRole = mRoleNames.key(role.toUtf8(), -1);
- if (intRole >= 0)
- return setData(index, value, intRole);
- return false;
-}
-
-bool QQmlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- const int row = index.row();
- if (row < 0 || row >= rowCount())
- return false;
-
- const int column = index.column();
- if (column < 0 || column >= columnCount())
- return false;
-
- const QString roleName = QString::fromUtf8(mRoleNames.value(role));
-
- qCDebug(lcTableModel).nospace() << "setData() called with index "
- << index << ", value " << value << " and role " << roleName;
-
- // Verify that the role exists for this column.
- const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
- if (!columnMetadata.roles.contains(roleName)) {
- qmlWarning(this) << "setData(): no role named \"" << roleName
- << "\" at column index " << column << ". The available roles for that column are: "
- << columnMetadata.roles.keys();
- return false;
- }
-
- // Verify that the type of the value is what we expect.
- // If the value set is not of the expected type, we can try to convert it automatically.
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- QVariant effectiveValue = value;
- if (value.type() != roleData.type) {
- if (!value.canConvert(int(roleData.type))) {
- qmlWarning(this).nospace() << "setData(): the value " << value
- << " set at row " << row << " column " << column << " with role " << roleName
- << " cannot be converted to " << roleData.typeName;
- return false;
- }
-
- if (!effectiveValue.convert(int(roleData.type))) {
- qmlWarning(this).nospace() << "setData(): failed converting value " << value
- << " set at row " << row << " column " << column << " with role " << roleName
- << " to " << roleData.typeName;
- return false;
- }
- }
-
- if (roleData.isStringRole) {
- // We know the data structure, so we can set it for the user.
- QVariantMap modifiedRow = mRows.at(row).toMap();
- modifiedRow[roleData.name] = value;
-
- mRows[row] = modifiedRow;
- } else {
- // We don't know the data structure, so the user has to modify their data themselves.
- auto engine = qmlEngine(this);
- auto args = QJSValueList()
- // arg 0: modelIndex.
- << engine->toScriptValue(index)
- // arg 1: cellData.
- << engine->toScriptValue(value);
- // Do the actual setting.
- QJSValue setter = mColumns.at(column)->setterAtRole(roleName);
- setter.call(args);
-
- /*
- The chain of events so far:
-
- - User did e.g.: model.edit = textInput.text
- - setData() is called
- - setData() calls the setter
- (remember that we need to emit the dataChanged() signal,
- which is why the user can't just set the data directly in the delegate)
-
- Now the user's setter function has modified *their* copy of the
- data, but *our* copy of the data is old. Imagine the getters and setters looked like this:
-
- display: function(modelIndex) { return rows[modelIndex.row][1].amount }
- setDisplay: function(modelIndex, cellData) { rows[modelIndex.row][1].amount = cellData }
-
- We don't know the structure of the user's data, so we can't just do
- what we do above for the isStringRole case:
-
- modifiedRow[column][roleName] = value
-
- This means that, besides getting the implicit row count when rows is initially set,
- our copy of the data is unused when it comes to complex columns.
-
- Another point to note is that we can't pass rowData in to the getter as a convenience,
- because we would be passing in *our* copy of the row, which is not up-to-date.
- Since the user already has access to the data, it's not a big deal for them to do:
-
- display: function(modelIndex) { return rows[modelIndex.row][1].amount }
-
- instead of:
-
- display: function(modelIndex, rowData) { return rowData[1].amount }
- */
- }
-
- QVector<int> rolesChanged;
- rolesChanged.append(role);
- emit dataChanged(index, index, rolesChanged);
-
- return true;
-}
-
-QHash<int, QByteArray> QQmlTableModel::roleNames() const
-{
- return mRoleNames;
-}
-
-QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata()
-{
-}
-
-QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata(
- bool isStringRole, const QString &name, QVariant::Type type, const QString &typeName) :
- isStringRole(isStringRole),
- name(name),
- type(type),
- typeName(typeName)
-{
-}
-
-bool QQmlTableModel::ColumnRoleMetadata::isValid() const
-{
- return !name.isEmpty();
-}
-
-bool QQmlTableModel::validateRowType(const char *functionName, const QVariant &row) const
-{
- if (!row.canConvert<QJSValue>()) {
- qmlWarning(this) << functionName << ": expected \"row\" argument to be a QJSValue,"
- << " but got " << row.typeName() << " instead:\n" << row;
- return false;
- }
-
- const QJSValue rowAsJSValue = row.value<QJSValue>();
- if (!rowAsJSValue.isObject() && !rowAsJSValue.isArray()) {
- qmlWarning(this) << functionName << ": expected \"row\" argument "
- << "to be an object or array, but got:\n" << rowAsJSValue.toString();
- return false;
- }
-
- return true;
-}
-
-bool QQmlTableModel::validateNewRow(const char *functionName, const QVariant &row,
- int rowIndex, NewRowOperationFlag operation) const
-{
- if (mColumnMetadata.isEmpty()) {
- // There is no column metadata, so we have nothing to validate the row against.
- // Rows have to be added before we can gather metadata from them, so just this
- // once we'll return true to allow the rows to be added.
- return true;
- }
-
- // Don't require each row to be a QJSValue when setting all rows,
- // as they won't be; they'll be QVariantMap.
- if (operation != SetRowsOperation && !validateRowType(functionName, row))
- return false;
-
- if (operation == OtherOperation) {
- // Inserting/setting.
- if (rowIndex < 0) {
- qmlWarning(this) << functionName << ": \"rowIndex\" cannot be negative";
- return false;
- }
-
- if (rowIndex > mRowCount) {
- qmlWarning(this) << functionName << ": \"rowIndex\" " << rowIndex
- << " is greater than rowCount() of " << mRowCount;
- return false;
- }
- }
-
- const QVariant rowAsVariant = operation == SetRowsOperation
- ? row : row.value<QJSValue>().toVariant();
- if (rowAsVariant.type() != QVariant::Map) {
- qmlWarning(this) << functionName << ": row manipulation functions "
- << "do not support complex rows (row index: " << rowIndex << ")";
- return false;
- }
-
- const QVariantMap rowAsMap = rowAsVariant.toMap();
- const int columnCount = rowAsMap.size();
- if (columnCount < mColumnCount) {
- qmlWarning(this) << functionName << ": expected " << mColumnCount
- << " columns, but only got " << columnCount;
- return false;
- }
-
- // We can't validate complex structures, but we can make sure that
- // each simple string-based role in each column is correct.
- for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
- QQmlTableModelColumn *column = mColumns.at(columnIndex);
- const QHash<QString, QJSValue> getters = column->getters();
- const auto roleNames = getters.keys();
- const ColumnMetadata columnMetadata = mColumnMetadata.at(columnIndex);
- for (const QString &roleName : roleNames) {
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- if (!roleData.isStringRole)
- continue;
-
- if (!rowAsMap.contains(roleData.name)) {
- qmlWarning(this).quote() << functionName << ": expected a property named "
- << roleData.name << " in row at index " << rowIndex << ", but couldn't find one";
- return false;
- }
-
- const QVariant rolePropertyValue = rowAsMap.value(roleData.name);
- if (rolePropertyValue.type() != roleData.type) {
- qmlWarning(this).quote() << functionName << ": expected the property named "
- << roleData.name << " to be of type " << roleData.typeName
- << ", but got " << QString::fromLatin1(rolePropertyValue.typeName()) << " instead";
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool QQmlTableModel::validateRowIndex(const char *functionName, const char *argumentName, int rowIndex) const
-{
- if (rowIndex < 0) {
- qmlWarning(this) << functionName << ": \"" << argumentName << "\" cannot be negative";
- return false;
- }
-
- if (rowIndex >= mRowCount) {
- qmlWarning(this) << functionName << ": \"" << argumentName
- << "\" " << rowIndex << " is greater than or equal to rowCount() of " << mRowCount;
- return false;
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmltablemodel_p.h b/src/qml/types/qqmltablemodel_p.h
deleted file mode 100644
index a1bb97e7d4..0000000000
--- a/src/qml/types/qqmltablemodel_p.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEMODEL_P_H
-#define QQMLTABLEMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QObject>
-#include <QtCore/QAbstractTableModel>
-#include <QtQml/qqml.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-#include <QtQml/private/qqmltablemodelcolumn_p.h>
-#include <QtQml/QJSValue>
-#include <QtQml/QQmlListProperty>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL)
- Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged FINAL)
- Q_PROPERTY(QVariant rows READ rows WRITE setRows NOTIFY rowsChanged FINAL)
- Q_PROPERTY(QQmlListProperty<QQmlTableModelColumn> columns READ columns CONSTANT FINAL)
- Q_INTERFACES(QQmlParserStatus)
- Q_CLASSINFO("DefaultProperty", "columns")
-
-public:
- QQmlTableModel(QObject *parent = nullptr);
- ~QQmlTableModel() override;
-
- QVariant rows() const;
- void setRows(const QVariant &rows);
-
- Q_INVOKABLE void appendRow(const QVariant &row);
- Q_INVOKABLE void clear();
- Q_INVOKABLE QVariant getRow(int rowIndex);
- Q_INVOKABLE void insertRow(int rowIndex, const QVariant &row);
- Q_INVOKABLE void moveRow(int fromRowIndex, int toRowIndex, int rows = 1);
- Q_INVOKABLE void removeRow(int rowIndex, int rows = 1);
- Q_INVOKABLE void setRow(int rowIndex, const QVariant &row);
-
- QQmlListProperty<QQmlTableModelColumn> columns();
-
- static void columns_append(QQmlListProperty<QQmlTableModelColumn> *property, QQmlTableModelColumn *value);
- static int columns_count(QQmlListProperty<QQmlTableModelColumn> *property);
- static QQmlTableModelColumn *columns_at(QQmlListProperty<QQmlTableModelColumn> *property, int index);
- static void columns_clear(QQmlListProperty<QQmlTableModelColumn> *property);
-
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
- Q_INVOKABLE QVariant data(const QModelIndex &index, const QString &role) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- Q_INVOKABLE bool setData(const QModelIndex &index, const QString &role, const QVariant &value);
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole) override;
- QHash<int, QByteArray> roleNames() const override;
-
-Q_SIGNALS:
- void columnCountChanged();
- void rowCountChanged();
- void rowsChanged();
-
-private:
- class ColumnRoleMetadata
- {
- public:
- ColumnRoleMetadata();
- ColumnRoleMetadata(bool isStringRole, const QString &name, QVariant::Type type, const QString &typeName);
-
- bool isValid() const;
-
- // If this is false, it's a function role.
- bool isStringRole = false;
- QString name;
- QVariant::Type type = QVariant::Invalid;
- QString typeName;
- };
-
- struct ColumnMetadata
- {
- // Key = role name that will be made visible to the delegate
- // Value = metadata about that role, including actual name in the model data, type, etc.
- QHash<QString, ColumnRoleMetadata> roles;
- };
-
- enum NewRowOperationFlag {
- OtherOperation, // insert(), set(), etc.
- SetRowsOperation,
- AppendOperation
- };
-
- void doSetRows(const QVariantList &rowsAsVariantList);
- ColumnRoleMetadata fetchColumnRoleData(const QString &roleNameKey,
- QQmlTableModelColumn *tableModelColumn, int columnIndex) const;
- void fetchColumnMetadata();
-
- bool validateRowType(const char *functionName, const QVariant &row) const;
- bool validateNewRow(const char *functionName, const QVariant &row,
- int rowIndex, NewRowOperationFlag operation = OtherOperation) const;
- bool validateRowIndex(const char *functionName, const char *argumentName, int rowIndex) const;
-
- void doInsert(int rowIndex, const QVariant &row);
-
- void classBegin() override;
- void componentComplete() override;
-
- bool componentCompleted = false;
- QVariantList mRows;
- QList<QQmlTableModelColumn *> mColumns;
- int mRowCount = 0;
- int mColumnCount = 0;
- // Each entry contains information about the properties of the column at that index.
- QVector<ColumnMetadata> mColumnMetadata;
- // key = property index (0 to number of properties across all columns)
- // value = role name
- QHash<int, QByteArray> mRoleNames;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTableModel)
-
-#endif // QQMLTABLEMODEL_P_H
diff --git a/src/qml/types/qqmltablemodelcolumn.cpp b/src/qml/types/qqmltablemodelcolumn.cpp
deleted file mode 100644
index 93da0642de..0000000000
--- a/src/qml/types/qqmltablemodelcolumn.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltablemodelcolumn_p.h"
-
-#include <QtQml/qqmlinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype TableModelColumn
- \instantiates QQmlTableModelColumn
- \inqmlmodule Qt.labs.qmlmodels
- \brief Represents a column in a model.
- \since 5.14
-
- \section1 Supported Roles
-
- TableModelColumn supports all of \l {Qt::ItemDataRole}{Qt's roles},
- with the exception of \c Qt::InitialSortOrderRole.
-
- \sa TableModel, TableView
-*/
-
-static const QString displayRoleName = QStringLiteral("display");
-static const QString decorationRoleName = QStringLiteral("decoration");
-static const QString editRoleName = QStringLiteral("edit");
-static const QString toolTipRoleName = QStringLiteral("toolTip");
-static const QString statusTipRoleName = QStringLiteral("statusTip");
-static const QString whatsThisRoleName = QStringLiteral("whatsThis");
-
-static const QString fontRoleName = QStringLiteral("font");
-static const QString textAlignmentRoleName = QStringLiteral("textAlignment");
-static const QString backgroundRoleName = QStringLiteral("background");
-static const QString foregroundRoleName = QStringLiteral("foreground");
-static const QString checkStateRoleName = QStringLiteral("checkState");
-
-static const QString accessibleTextRoleName = QStringLiteral("accessibleText");
-static const QString accessibleDescriptionRoleName = QStringLiteral("accessibleDescription");
-
-static const QString sizeHintRoleName = QStringLiteral("sizeHint");
-
-
-QQmlTableModelColumn::QQmlTableModelColumn(QObject *parent)
- : QObject(parent)
-{
-}
-
-QQmlTableModelColumn::~QQmlTableModelColumn()
-{
-}
-
-#define DEFINE_ROLE_PROPERTIES(getterGetterName, getterSetterName, getterSignal, setterGetterName, setterSetterName, setterSignal, roleName) \
-QJSValue QQmlTableModelColumn::getterGetterName() const \
-{ \
- return mGetters.value(roleName); \
-} \
-\
-void QQmlTableModelColumn::getterSetterName(const QJSValue &stringOrFunction) \
-{ \
- if (!stringOrFunction.isString() && !stringOrFunction.isCallable()) { \
- qmlWarning(this).quote() << "getter for " << roleName << " must be a function"; \
- return; \
- } \
- if (stringOrFunction.strictlyEquals(decoration())) \
- return; \
-\
- mGetters[roleName] = stringOrFunction; \
- emit decorationChanged(); \
-} \
-\
-QJSValue QQmlTableModelColumn::setterGetterName() const \
-{ \
- return mSetters.value(roleName); \
-} \
-\
-void QQmlTableModelColumn::setterSetterName(const QJSValue &function) \
-{ \
- if (!function.isCallable()) { \
- qmlWarning(this).quote() << "setter for " << roleName << " must be a function"; \
- return; \
- } \
-\
- if (function.strictlyEquals(getSetDisplay())) \
- return; \
-\
- mSetters[roleName] = function; \
- emit setDisplayChanged(); \
-}
-
-DEFINE_ROLE_PROPERTIES(display, setDisplay, displayChanged,
- getSetDisplay, setSetDisplay, setDisplayChanged, displayRoleName)
-DEFINE_ROLE_PROPERTIES(decoration, setDecoration, decorationChanged,
- getSetDecoration, setSetDecoration, setDecorationChanged, decorationRoleName)
-DEFINE_ROLE_PROPERTIES(edit, setEdit, editChanged,
- getSetEdit, setSetEdit, setEditChanged, editRoleName)
-DEFINE_ROLE_PROPERTIES(toolTip, setToolTip, toolTipChanged,
- getSetToolTip, setSetToolTip, setToolTipChanged, toolTipRoleName)
-DEFINE_ROLE_PROPERTIES(statusTip, setStatusTip, statusTipChanged,
- getSetStatusTip, setSetStatusTip, setStatusTipChanged, statusTipRoleName)
-DEFINE_ROLE_PROPERTIES(whatsThis, setWhatsThis, whatsThisChanged,
- getSetWhatsThis, setSetWhatsThis, setWhatsThisChanged, whatsThisRoleName)
-
-DEFINE_ROLE_PROPERTIES(font, setFont, fontChanged,
- getSetFont, setSetFont, setFontChanged, fontRoleName)
-DEFINE_ROLE_PROPERTIES(textAlignment, setTextAlignment, textAlignmentChanged,
- getSetTextAlignment, setSetTextAlignment, setTextAlignmentChanged, textAlignmentRoleName)
-DEFINE_ROLE_PROPERTIES(background, setBackground, backgroundChanged,
- getSetBackground, setSetBackground, setBackgroundChanged, backgroundRoleName)
-DEFINE_ROLE_PROPERTIES(foreground, setForeground, foregroundChanged,
- getSetForeground, setSetForeground, setForegroundChanged, foregroundRoleName)
-DEFINE_ROLE_PROPERTIES(checkState, setCheckState, checkStateChanged,
- getSetCheckState, setSetCheckState, setCheckStateChanged, checkStateRoleName)
-
-DEFINE_ROLE_PROPERTIES(accessibleText, setAccessibleText, accessibleTextChanged,
- getSetAccessibleText, setSetAccessibleText, setAccessibleTextChanged, accessibleTextRoleName)
-DEFINE_ROLE_PROPERTIES(accessibleDescription, setAccessibleDescription, accessibleDescriptionChanged,
- getSetAccessibleDescription, setSetAccessibleDescription, setAccessibleDescriptionChanged, accessibleDescriptionRoleName)
-
-DEFINE_ROLE_PROPERTIES(sizeHint, setSizeHint, sizeHintChanged,
- getSetSizeHint, setSetSizeHint, setSizeHintChanged, sizeHintRoleName)
-
-QJSValue QQmlTableModelColumn::getterAtRole(const QString &roleName)
-{
- auto it = mGetters.find(roleName);
- if (it == mGetters.end())
- return QJSValue();
- return *it;
-}
-
-QJSValue QQmlTableModelColumn::setterAtRole(const QString &roleName)
-{
- auto it = mSetters.find(roleName);
- if (it == mSetters.end())
- return QJSValue();
- return *it;
-}
-
-const QHash<QString, QJSValue> QQmlTableModelColumn::getters() const
-{
- return mGetters;
-}
-
-const QHash<int, QString> QQmlTableModelColumn::supportedRoleNames()
-{
- QHash<int, QString> names;
- names[Qt::DisplayRole] = QLatin1String("display");
- names[Qt::DecorationRole] = QLatin1String("decoration");
- names[Qt::EditRole] = QLatin1String("edit");
- names[Qt::ToolTipRole] = QLatin1String("toolTip");
- names[Qt::StatusTipRole] = QLatin1String("statusTip");
- names[Qt::WhatsThisRole] = QLatin1String("whatsThis");
- names[Qt::FontRole] = QLatin1String("font");
- names[Qt::TextAlignmentRole] = QLatin1String("textAlignment");
- names[Qt::BackgroundRole] = QLatin1String("background");
- names[Qt::ForegroundRole] = QLatin1String("foreground");
- names[Qt::CheckStateRole] = QLatin1String("checkState");
- names[Qt::AccessibleTextRole] = QLatin1String("accessibleText");
- names[Qt::AccessibleDescriptionRole] = QLatin1String("accessibleDescription");
- names[Qt::SizeHintRole] = QLatin1String("sizeHint");
- return names;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmltablemodelcolumn_p.h b/src/qml/types/qqmltablemodelcolumn_p.h
deleted file mode 100644
index 41c02482c0..0000000000
--- a/src/qml/types/qqmltablemodelcolumn_p.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEMODELCOLUMN_P_H
-#define QQMLTABLEMODELCOLUMN_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QObject>
-#include <QtQml/qqml.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-#include <QtQml/qjsvalue.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_AUTOTEST_EXPORT QQmlTableModelColumn : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QJSValue display READ display WRITE setDisplay NOTIFY displayChanged FINAL)
- Q_PROPERTY(QJSValue setDisplay READ getSetDisplay WRITE setSetDisplay NOTIFY setDisplayChanged)
- Q_PROPERTY(QJSValue decoration READ decoration WRITE setDecoration NOTIFY decorationChanged FINAL)
- Q_PROPERTY(QJSValue setDecoration READ getSetDecoration WRITE setSetDecoration NOTIFY setDecorationChanged FINAL)
- Q_PROPERTY(QJSValue edit READ edit WRITE setEdit NOTIFY editChanged FINAL)
- Q_PROPERTY(QJSValue setEdit READ getSetEdit WRITE setSetEdit NOTIFY setEditChanged FINAL)
- Q_PROPERTY(QJSValue toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged FINAL)
- Q_PROPERTY(QJSValue setToolTip READ getSetToolTip WRITE setSetToolTip NOTIFY setToolTipChanged FINAL)
- Q_PROPERTY(QJSValue statusTip READ statusTip WRITE setStatusTip NOTIFY statusTipChanged FINAL)
- Q_PROPERTY(QJSValue setStatusTip READ getSetStatusTip WRITE setSetStatusTip NOTIFY setStatusTipChanged FINAL)
- Q_PROPERTY(QJSValue whatsThis READ whatsThis WRITE setWhatsThis NOTIFY whatsThisChanged FINAL)
- Q_PROPERTY(QJSValue setWhatsThis READ getSetWhatsThis WRITE setSetWhatsThis NOTIFY setWhatsThisChanged FINAL)
-
- Q_PROPERTY(QJSValue font READ font WRITE setFont NOTIFY fontChanged FINAL)
- Q_PROPERTY(QJSValue setFont READ getSetFont WRITE setSetFont NOTIFY setFontChanged FINAL)
- Q_PROPERTY(QJSValue textAlignment READ textAlignment WRITE setTextAlignment NOTIFY textAlignmentChanged FINAL)
- Q_PROPERTY(QJSValue setTextAlignment READ getSetTextAlignment WRITE setSetTextAlignment NOTIFY setTextAlignmentChanged FINAL)
- Q_PROPERTY(QJSValue background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
- Q_PROPERTY(QJSValue setBackground READ getSetBackground WRITE setSetBackground NOTIFY setBackgroundChanged FINAL)
- Q_PROPERTY(QJSValue foreground READ foreground WRITE setForeground NOTIFY foregroundChanged FINAL)
- Q_PROPERTY(QJSValue setForeground READ getSetForeground WRITE setSetForeground NOTIFY setForegroundChanged FINAL)
- Q_PROPERTY(QJSValue checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL)
- Q_PROPERTY(QJSValue setCheckState READ getSetCheckState WRITE setSetCheckState NOTIFY setCheckStateChanged FINAL)
-
- Q_PROPERTY(QJSValue accessibleText READ accessibleText WRITE setAccessibleText NOTIFY accessibleTextChanged FINAL)
- Q_PROPERTY(QJSValue setAccessibleText READ getSetAccessibleText WRITE setSetAccessibleText NOTIFY setAccessibleTextChanged FINAL)
- Q_PROPERTY(QJSValue accessibleDescription READ accessibleDescription
- WRITE setAccessibleDescription NOTIFY accessibleDescriptionChanged FINAL)
- Q_PROPERTY(QJSValue setAccessibleDescription READ getSetAccessibleDescription
- WRITE setSetAccessibleDescription NOTIFY setAccessibleDescriptionChanged FINAL)
-
- Q_PROPERTY(QJSValue sizeHint READ sizeHint WRITE setSizeHint NOTIFY sizeHintChanged FINAL)
- Q_PROPERTY(QJSValue setSizeHint READ getSetSizeHint WRITE setSetSizeHint NOTIFY setSizeHintChanged FINAL)
-
-public:
- QQmlTableModelColumn(QObject *parent = nullptr);
- ~QQmlTableModelColumn() override;
-
- QJSValue display() const;
- void setDisplay(const QJSValue &stringOrFunction);
- QJSValue getSetDisplay() const;
- void setSetDisplay(const QJSValue &function);
-
- QJSValue decoration() const;
- void setDecoration(const QJSValue &stringOrFunction);
- QJSValue getSetDecoration() const;
- void setSetDecoration(const QJSValue &function);
-
- QJSValue edit() const;
- void setEdit(const QJSValue &stringOrFunction);
- QJSValue getSetEdit() const;
- void setSetEdit(const QJSValue &function);
-
- QJSValue toolTip() const;
- void setToolTip(const QJSValue &stringOrFunction);
- QJSValue getSetToolTip() const;
- void setSetToolTip(const QJSValue &function);
-
- QJSValue statusTip() const;
- void setStatusTip(const QJSValue &stringOrFunction);
- QJSValue getSetStatusTip() const;
- void setSetStatusTip(const QJSValue &function);
-
- QJSValue whatsThis() const;
- void setWhatsThis(const QJSValue &stringOrFunction);
- QJSValue getSetWhatsThis() const;
- void setSetWhatsThis(const QJSValue &function);
-
- QJSValue font() const;
- void setFont(const QJSValue &stringOrFunction);
- QJSValue getSetFont() const;
- void setSetFont(const QJSValue &function);
-
- QJSValue textAlignment() const;
- void setTextAlignment(const QJSValue &stringOrFunction);
- QJSValue getSetTextAlignment() const;
- void setSetTextAlignment(const QJSValue &function);
-
- QJSValue background() const;
- void setBackground(const QJSValue &stringOrFunction);
- QJSValue getSetBackground() const;
- void setSetBackground(const QJSValue &function);
-
- QJSValue foreground() const;
- void setForeground(const QJSValue &stringOrFunction);
- QJSValue getSetForeground() const;
- void setSetForeground(const QJSValue &function);
-
- QJSValue checkState() const;
- void setCheckState(const QJSValue &stringOrFunction);
- QJSValue getSetCheckState() const;
- void setSetCheckState(const QJSValue &function);
-
- QJSValue accessibleText() const;
- void setAccessibleText(const QJSValue &stringOrFunction);
- QJSValue getSetAccessibleText() const;
- void setSetAccessibleText(const QJSValue &function);
-
- QJSValue accessibleDescription() const;
- void setAccessibleDescription(const QJSValue &stringOrFunction);
- QJSValue getSetAccessibleDescription() const;
- void setSetAccessibleDescription(const QJSValue &function);
-
- QJSValue sizeHint() const;
- void setSizeHint(const QJSValue &stringOrFunction);
- QJSValue getSetSizeHint() const;
- void setSetSizeHint(const QJSValue &function);
-
- QJSValue getterAtRole(const QString &roleName);
- QJSValue setterAtRole(const QString &roleName);
-
- const QHash<QString, QJSValue> getters() const;
-
- static const QHash<int, QString> supportedRoleNames();
-
-Q_SIGNALS:
- void indexChanged();
- void displayChanged();
- void setDisplayChanged();
- void decorationChanged();
- void setDecorationChanged();
- void editChanged();
- void setEditChanged();
- void toolTipChanged();
- void setToolTipChanged();
- void statusTipChanged();
- void setStatusTipChanged();
- void whatsThisChanged();
- void setWhatsThisChanged();
-
- void fontChanged();
- void setFontChanged();
- void textAlignmentChanged();
- void setTextAlignmentChanged();
- void backgroundChanged();
- void setBackgroundChanged();
- void foregroundChanged();
- void setForegroundChanged();
- void checkStateChanged();
- void setCheckStateChanged();
-
- void accessibleTextChanged();
- void setAccessibleTextChanged();
- void accessibleDescriptionChanged();
- void setAccessibleDescriptionChanged();
- void sizeHintChanged();
- void setSizeHintChanged();
-
-private:
- int mIndex = -1;
-
- // We store these in hashes because QQuickTableModel needs string-based lookup in certain situations.
- QHash<QString, QJSValue> mGetters;
- QHash<QString, QJSValue> mSetters;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTableModelColumn)
-
-#endif // QQMLTABLEMODELCOLUMN_P_H
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
deleted file mode 100644
index 03539d8737..0000000000
--- a/src/qml/types/qquickpackage.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qquickpackage_p.h"
-
-#include <private/qobject_p.h>
-#include <private/qqmlguard_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype Package
- \instantiates QQuickPackage
- \inqmlmodule QtQuick
- \ingroup qtquick-views
- \brief Specifies a collection of named items.
-
- The Package type is used in conjunction with
- DelegateModel to enable delegates with a shared context
- to be provided to multiple views.
-
- Any item within a Package may be assigned a name via the
- \l{Package::name}{Package.name} attached property.
-
- The example below creates a Package containing two named items;
- \e list and \e grid. The third item in the package (the \l Rectangle) is parented to whichever
- delegate it should appear in. This allows an item to move
- between views.
-
- \snippet package/Delegate.qml 0
-
- These named items are used as the delegates by the two views who
- reference the special \l{DelegateModel::parts} property to select
- a model which provides the chosen delegate.
-
- \snippet package/view.qml 0
-
- \sa {Qt Quick Examples - Views}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
-*/
-
-/*!
- \qmlattachedproperty string QtQuick::Package::name
- This attached property holds the name of an item within a Package.
-*/
-
-
-class QQuickPackagePrivate : public QObjectPrivate
-{
-public:
- QQuickPackagePrivate() {}
-
- struct DataGuard : public QQmlGuard<QObject>
- {
- DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QQmlGuard<QObject>&)*this = obj; }
- QList<DataGuard> *list;
- void objectDestroyed(QObject *) override {
- // we assume priv will always be destroyed after objectDestroyed calls
- list->removeOne(*this);
- }
- };
-
- QList<DataGuard> dataList;
- static void data_append(QQmlListProperty<QObject> *prop, QObject *o) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- list->append(DataGuard(o, list));
- }
- static void data_clear(QQmlListProperty<QObject> *prop) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- list->clear();
- }
- static QObject *data_at(QQmlListProperty<QObject> *prop, int index) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- return list->at(index);
- }
- static int data_count(QQmlListProperty<QObject> *prop) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- return list->count();
- }
-};
-
-QHash<QObject *, QQuickPackageAttached *> QQuickPackageAttached::attached;
-
-QQuickPackageAttached::QQuickPackageAttached(QObject *parent)
-: QObject(parent)
-{
- attached.insert(parent, this);
-}
-
-QQuickPackageAttached::~QQuickPackageAttached()
-{
- attached.remove(parent());
-}
-
-QString QQuickPackageAttached::name() const
-{
- return _name;
-}
-
-void QQuickPackageAttached::setName(const QString &n)
-{
- _name = n;
-}
-
-QQuickPackage::QQuickPackage(QObject *parent)
- : QObject(*(new QQuickPackagePrivate), parent)
-{
-}
-
-QQuickPackage::~QQuickPackage()
-{
-}
-
-QQmlListProperty<QObject> QQuickPackage::data()
-{
- Q_D(QQuickPackage);
- return QQmlListProperty<QObject>(this, &d->dataList, QQuickPackagePrivate::data_append,
- QQuickPackagePrivate::data_count,
- QQuickPackagePrivate::data_at,
- QQuickPackagePrivate::data_clear);
-}
-
-bool QQuickPackage::hasPart(const QString &name)
-{
- Q_D(QQuickPackage);
- for (int ii = 0; ii < d->dataList.count(); ++ii) {
- QObject *obj = d->dataList.at(ii);
- QQuickPackageAttached *a = QQuickPackageAttached::attached.value(obj);
- if (a && a->name() == name)
- return true;
- }
- return false;
-}
-
-QObject *QQuickPackage::part(const QString &name)
-{
- Q_D(QQuickPackage);
- if (name.isEmpty() && !d->dataList.isEmpty())
- return d->dataList.at(0);
-
- for (int ii = 0; ii < d->dataList.count(); ++ii) {
- QObject *obj = d->dataList.at(ii);
- QQuickPackageAttached *a = QQuickPackageAttached::attached.value(obj);
- if (a && a->name() == name)
- return obj;
- }
-
- if (name == QLatin1String("default") && !d->dataList.isEmpty())
- return d->dataList.at(0);
-
- return nullptr;
-}
-
-QQuickPackageAttached *QQuickPackage::qmlAttachedProperties(QObject *o)
-{
- return new QQuickPackageAttached(o);
-}
-
-
-
-QT_END_NAMESPACE
-
-#include "moc_qquickpackage_p.cpp"
diff --git a/src/qml/types/qquickpackage_p.h b/src/qml/types/qquickpackage_p.h
deleted file mode 100644
index 122c7fcb30..0000000000
--- a/src/qml/types/qquickpackage_p.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKPACKAGE_H
-#define QQUICKPACKAGE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQuickPackagePrivate;
-class QQuickPackageAttached;
-class Q_AUTOTEST_EXPORT QQuickPackage : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQuickPackage)
-
- Q_CLASSINFO("DefaultProperty", "data")
- Q_PROPERTY(QQmlListProperty<QObject> data READ data)
-
-public:
- QQuickPackage(QObject *parent=nullptr);
- virtual ~QQuickPackage();
-
- QQmlListProperty<QObject> data();
-
- QObject *part(const QString & = QString());
- bool hasPart(const QString &);
-
- static QQuickPackageAttached *qmlAttachedProperties(QObject *);
-};
-
-class QQuickPackageAttached : public QObject
-{
-Q_OBJECT
-Q_PROPERTY(QString name READ name WRITE setName)
-public:
- QQuickPackageAttached(QObject *parent);
- virtual ~QQuickPackageAttached();
-
- QString name() const;
- void setName(const QString &n);
-
- static QHash<QObject *, QQuickPackageAttached *> attached;
-private:
- QString _name;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQuickPackage)
-QML_DECLARE_TYPEINFO(QQuickPackage, QML_HAS_ATTACHED_PROPERTIES)
-
-#endif // QQUICKPACKAGE_H
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index 5a56208dc4..ba11271d66 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,27 +1,12 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
- $$PWD/qqmlmodelsmodule.cpp \
- $$PWD/qqmlmodelindexvaluetype.cpp \
- $$PWD/qqmlobjectmodel.cpp \
- $$PWD/qquickpackage.cpp \
- $$PWD/qqmlinstantiator.cpp \
- $$PWD/qqmltableinstancemodel.cpp \
- $$PWD/qqmltablemodel.cpp \
- $$PWD/qqmltablemodelcolumn.cpp
+ $$PWD/qqmlmodelindexvaluetype.cpp
HEADERS += \
$$PWD/qqmlbind_p.h \
$$PWD/qqmlconnections_p.h \
- $$PWD/qqmlmodelsmodule_p.h \
- $$PWD/qqmlmodelindexvaluetype_p.h \
- $$PWD/qqmlobjectmodel_p.h \
- $$PWD/qquickpackage_p.h \
- $$PWD/qqmlinstantiator_p.h \
- $$PWD/qqmlinstantiator_p_p.h \
- $$PWD/qqmltableinstancemodel_p.h \
- $$PWD/qqmltablemodel_p.h \
- $$PWD/qqmltablemodelcolumn_p.h
+ $$PWD/qqmlmodelindexvaluetype_p.h
qtConfig(qml-worker-script) {
SOURCES += \
@@ -30,28 +15,6 @@ qtConfig(qml-worker-script) {
$$PWD/qquickworkerscript_p.h
}
-qtConfig(qml-list-model) {
- SOURCES += \
- $$PWD/qqmllistmodel.cpp \
- $$PWD/qqmllistmodelworkeragent.cpp
-
- HEADERS += \
- $$PWD/qqmllistmodel_p.h \
- $$PWD/qqmllistmodel_p_p.h \
- $$PWD/qqmllistmodelworkeragent_p.h
-}
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmldelegatecomponent.cpp
-
- HEADERS += \
- $$PWD/qqmldelegatemodel_p.h \
- $$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmldelegatecomponent_p.h
-}
-
qtConfig(qml-animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
deleted file mode 100644
index f991ae0a69..0000000000
--- a/src/qml/util/qqmladaptormodel.cpp
+++ /dev/null
@@ -1,1037 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmladaptormodel_p.h"
-
-#include <private/qqmldelegatemodel_p_p.h>
-#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmlproperty_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlAdaptorModelEngineData : public QV8Engine::Deletable
-{
-public:
- QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4);
- ~QQmlAdaptorModelEngineData();
-
- QV4::ExecutionEngine *v4;
- QV4::PersistentValue listItemProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
-
-static QV4::ReturnedValue get_index(const QV4::FunctionObject *f, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(f);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- RETURN_RESULT(QV4::Encode(o->d()->item->index));
-}
-
-template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
-{
- builder->setFlags(QMetaObjectBuilder::DynamicMetaObject);
- builder->setClassName(T::staticMetaObject.className());
- builder->setSuperClass(&T::staticMetaObject);
- metaType->propertyOffset = T::staticMetaObject.propertyCount();
- metaType->signalOffset = T::staticMetaObject.methodCount();
-}
-
-static void addProperty(QMetaObjectBuilder *builder, int propertyId, const QByteArray &propertyName, const QByteArray &propertyType)
-{
- builder->addSignal("__" + QByteArray::number(propertyId) + "()");
- QMetaPropertyBuilder property = builder->addProperty(
- propertyName, propertyType, propertyId);
- property.setWritable(true);
-}
-
-class VDMModelDelegateDataType;
-
-class QQmlDMCachedModelData : public QQmlDelegateModelItem
-{
-public:
- QQmlDMCachedModelData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column);
-
- int metaCall(QMetaObject::Call call, int id, void **arguments);
-
- virtual QVariant value(int role) const = 0;
- virtual void setValue(int role, const QVariant &value) = 0;
-
- void setValue(const QString &role, const QVariant &value) override;
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
-
- static QV4::ReturnedValue get_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue set_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- VDMModelDelegateDataType *type;
- QVector<QVariant> cachedData;
-};
-
-class VDMModelDelegateDataType
- : public QQmlRefCount
- , public QQmlAdaptorModel::Accessors
- , public QAbstractDynamicMetaObject
-{
-public:
- VDMModelDelegateDataType(QQmlAdaptorModel *model)
- : model(model)
- , propertyOffset(0)
- , signalOffset(0)
- , hasModelData(false)
- {
- }
-
- bool notify(
- const QQmlAdaptorModel &,
- const QList<QQmlDelegateModelItem *> &items,
- int index,
- int count,
- const QVector<int> &roles) const override
- {
- bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
- if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
- QList<int> roleIds;
- for (const QByteArray &r : watchedRoles) {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
- if (it != roleNames.end())
- roleIds << it.value();
- }
- const_cast<VDMModelDelegateDataType *>(this)->watchedRoleIds = roleIds;
- }
-
- QVector<int> signalIndexes;
- for (int i = 0; i < roles.count(); ++i) {
- const int role = roles.at(i);
- if (!changed && watchedRoleIds.contains(role))
- changed = true;
-
- int propertyId = propertyRoles.indexOf(role);
- if (propertyId != -1)
- signalIndexes.append(propertyId + signalOffset);
- }
- if (roles.isEmpty()) {
- const int propertyRolesCount = propertyRoles.count();
- signalIndexes.reserve(propertyRolesCount);
- for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
- signalIndexes.append(propertyId + signalOffset);
- }
-
- for (int i = 0, c = items.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = items.at(i);
- const int idx = item->modelIndex();
- if (idx >= index && idx < index + count) {
- for (int i = 0; i < signalIndexes.count(); ++i)
- QMetaObject::activate(item, signalIndexes.at(i), nullptr);
- }
- }
- return changed;
- }
-
- void replaceWatchedRoles(
- QQmlAdaptorModel &,
- const QList<QByteArray> &oldRoles,
- const QList<QByteArray> &newRoles) const override
- {
- VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
-
- dataType->watchedRoleIds.clear();
- for (const QByteArray &oldRole : oldRoles)
- dataType->watchedRoles.removeOne(oldRole);
- dataType->watchedRoles += newRoles;
- }
-
- static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model;
- if (o->d()->item->index >= 0 && *model) {
- const QAbstractItemModel * const aim = model->aim();
- RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
- } else {
- RETURN_RESULT(QV4::Encode(false));
- }
- }
-
-
- void initializeConstructor(QQmlAdaptorModelEngineData *const data)
- {
- QV4::ExecutionEngine *v4 = data->v4;
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
- QV4::ScopedProperty p(scope);
-
- typedef QHash<QByteArray, int>::const_iterator iterator;
- for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
- const int propertyId = propertyRoles.indexOf(it.value());
- const QByteArray &propertyName = it.key();
-
- QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));
- p->setGetter(g);
- p->setSetter(s);
- proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
- }
- prototype.set(v4, proto);
- }
-
- // QAbstractDynamicMetaObject
-
- void objectDestroyed(QObject *) override
- {
- release();
- }
-
- int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
- {
- return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments);
- }
-
- QV4::PersistentValue prototype;
- QList<int> propertyRoles;
- QList<int> watchedRoleIds;
- QList<QByteArray> watchedRoles;
- QHash<QByteArray, int> roleNames;
- QQmlAdaptorModel *model;
- int propertyOffset;
- int signalOffset;
- bool hasModelData;
-};
-
-QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index, int row, int column)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , type(dataType)
-{
- if (index == -1)
- cachedData.resize(type->hasModelData ? 1 : type->propertyRoles.count());
-
- QObjectPrivate::get(this)->metaObject = type;
-
- type->addref();
-}
-
-int QQmlDMCachedModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
-{
- if (call == QMetaObject::ReadProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- if (!cachedData.isEmpty()) {
- *static_cast<QVariant *>(arguments[0]) = cachedData.at(
- type->hasModelData ? 0 : propertyIndex);
- }
- } else if (*type->model) {
- *static_cast<QVariant *>(arguments[0]) = value(type->propertyRoles.at(propertyIndex));
- }
- return -1;
- } else if (call == QMetaObject::WriteProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- const QMetaObject *meta = metaObject();
- if (cachedData.count() > 1) {
- cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, propertyIndex, nullptr);
- } else if (cachedData.count() == 1) {
- cachedData[0] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, 0, nullptr);
- QMetaObject::activate(this, meta, 1, nullptr);
- }
- } else if (*type->model) {
- setValue(type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
- }
- return -1;
- } else {
- return qt_metacall(call, id, arguments);
- }
-}
-
-void QQmlDMCachedModelData::setValue(const QString &role, const QVariant &value)
-{
- QHash<QByteArray, int>::iterator it = type->roleNames.find(role.toUtf8());
- if (it != type->roleNames.end()) {
- for (int i = 0; i < type->propertyRoles.count(); ++i) {
- if (type->propertyRoles.at(i) == *it) {
- cachedData[i] = value;
- return;
- }
- }
- }
-}
-
-bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &adaptorModel, int idx)
-{
- if (index == -1) {
- Q_ASSERT(idx >= 0);
- cachedData.clear();
- setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
- const QMetaObject *meta = metaObject();
- const int propertyCount = type->propertyRoles.count();
- for (int i = 0; i < propertyCount; ++i)
- QMetaObject::activate(this, meta, i, nullptr);
- return true;
- } else {
- return false;
- }
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
- if (o->d()->item->index == -1) {
- if (!modelData->cachedData.isEmpty()) {
- return scope.engine->fromVariant(
- modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId));
- }
- } else if (*modelData->type->model) {
- return scope.engine->fromVariant(
- modelData->value(modelData->type->propertyRoles.at(propertyId)));
- }
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return scope.engine->throwTypeError();
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- if (o->d()->item->index == -1) {
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
- if (!modelData->cachedData.isEmpty()) {
- if (modelData->cachedData.count() > 1) {
- modelData->cachedData[propertyId] = scope.engine->toVariant(argv[0], QVariant::Invalid);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
- } else if (modelData->cachedData.count() == 1) {
- modelData->cachedData[0] = scope.engine->toVariant(argv[0], QVariant::Invalid);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
- }
- }
- }
- return QV4::Encode::undefined();
-}
-
-//-----------------------------------------------------------------
-// QAbstractItemModel
-//-----------------------------------------------------------------
-
-class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
-{
- Q_OBJECT
- Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
-
-public:
- QQmlDMAbstractItemModelData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column)
- : QQmlDMCachedModelData(metaType, dataType, index, row, column)
- {
- }
-
- bool hasModelChildren() const
- {
- if (index >= 0 && *type->model) {
- const QAbstractItemModel * const model = type->model->aim();
- return model->hasChildren(model->index(row, column, type->model->rootIndex));
- } else {
- return false;
- }
- }
-
- QVariant value(int role) const override
- {
- return type->model->aim()->index(row, column, type->model->rootIndex).data(role);
- }
-
- void setValue(int role, const QVariant &value) override
- {
- type->model->aim()->setData(
- type->model->aim()->index(row, column, type->model->rootIndex), value, role);
- }
-
- QV4::ReturnedValue get() override
- {
- if (type->prototype.isUndefined()) {
- QQmlAdaptorModelEngineData * const data = engineData(v4);
- type->initializeConstructor(data);
- }
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, type->prototype.value());
- QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- o->setPrototypeOf(proto);
- ++scriptRef;
- return o.asReturnedValue();
- }
-};
-
-class VDMAbstractItemModelDataType : public VDMModelDelegateDataType
-{
-public:
- VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
- : VDMModelDelegateDataType(model)
- {
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.aim()->rowCount(model.rootIndex);
- }
-
- int columnCount(const QQmlAdaptorModel &model) const override
- {
- return model.aim()->columnCount(model.rootIndex);
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMAbstractItemModelDataType *>(this)->release();
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
- if (it != roleNames.end()) {
- return model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex).data(*it);
- } else if (role == QLatin1String("hasModelChildren")) {
- return QVariant(model.aim()->hasChildren(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex)));
- } else {
- return QVariant();
- }
- }
-
- QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
- {
- return model
- ? QVariant::fromValue(model.aim()->parent(model.rootIndex))
- : QVariant();
- }
-
- QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
- {
- return model
- ? QVariant::fromValue(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex))
- : QVariant();
- }
-
- bool canFetchMore(const QQmlAdaptorModel &model) const override
- {
- return model && model.aim()->canFetchMore(model.rootIndex);
- }
-
- void fetchMore(QQmlAdaptorModel &model) const override
- {
- if (model)
- model.aim()->fetchMore(model.rootIndex);
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return new QQmlDMAbstractItemModelData(metaType, dataType, index, row, column);
- }
-
- void initializeMetaType(QQmlAdaptorModel &model)
- {
- QMetaObjectBuilder builder;
- setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
-
- const QByteArray propertyType = QByteArrayLiteral("QVariant");
- const QHash<int, QByteArray> names = model.aim()->roleNames();
- for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
- const int propertyId = propertyRoles.count();
- propertyRoles.append(it.key());
- roleNames.insert(it.value(), it.key());
- addProperty(&builder, propertyId, it.value(), propertyType);
- }
- if (propertyRoles.count() == 1) {
- hasModelData = true;
- const int role = names.begin().key();
- const QByteArray propertyName = QByteArrayLiteral("modelData");
-
- propertyRoles.append(role);
- roleNames.insert(propertyName, role);
- addProperty(&builder, 1, propertyName, propertyType);
- }
-
- metaObject.reset(builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *metaObject;
- propertyCache.adopt(new QQmlPropertyCache(metaObject.data(), model.modelItemRevision));
- }
-};
-
-//-----------------------------------------------------------------
-// QQmlListAccessor
-//-----------------------------------------------------------------
-
-class QQmlDMListAccessorData : public QQmlDelegateModelItem
-{
- Q_OBJECT
- Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
-public:
- QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int index, int row, int column, const QVariant &value)
- : QQmlDelegateModelItem(metaType, accessor, index, row, column)
- , cachedData(value)
- {
- }
-
- QVariant modelData() const
- {
- return cachedData;
- }
-
- void setModelData(const QVariant &data)
- {
- if (data == cachedData)
- return;
-
- cachedData = data;
- emit modelDataChanged();
- }
-
- static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
- }
-
- static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return v4->throwTypeError();
-
- static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QVariant::Invalid));
- return QV4::Encode::undefined();
- }
-
- QV4::ReturnedValue get() override
- {
- QQmlAdaptorModelEngineData *data = engineData(v4);
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- QV4::ScopedObject p(scope, data->listItemProto.value());
- o->setPrototypeOf(p);
- ++scriptRef;
- return o.asReturnedValue();
- }
-
- void setValue(const QString &role, const QVariant &value) override
- {
- if (role == QLatin1String("modelData"))
- cachedData = value;
- }
-
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override
- {
- if (index == -1) {
- index = idx;
- cachedData = model.list.at(idx);
- emit modelIndexChanged();
- emit modelDataChanged();
- return true;
- } else {
- return false;
- }
- }
-
-
-Q_SIGNALS:
- void modelDataChanged();
-
-private:
- QVariant cachedData;
-};
-
-
-class VDMListDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- VDMListDelegateDataType()
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- {}
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMListDelegateDataType *>(this)->release();
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- return role == QLatin1String("modelData")
- ? model.list.at(index)
- : QVariant();
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
- if (!propertyCache) {
- dataType->propertyCache.adopt(new QQmlPropertyCache(
- &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision));
- }
-
- return new QQmlDMListAccessorData(
- metaType,
- dataType,
- index, row, column,
- index >= 0 && index < model.list.count() ? model.list.at(index) : QVariant());
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
- QVariant updatedModelData = model.list.at(listModelItem->index);
- listModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-//-----------------------------------------------------------------
-// QObject
-//-----------------------------------------------------------------
-
-class VDMObjectDelegateDataType;
-class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
-{
- Q_OBJECT
- Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
- Q_INTERFACES(QQmlAdaptorModelProxyInterface)
-public:
- QQmlDMObjectData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object);
-
- void setModelData(QObject *modelData)
- {
- if (modelData == object)
- return;
-
- object = modelData;
- emit modelDataChanged();
- }
-
- QObject *modelData() const { return object; }
- QObject *proxiedObject() override { return object; }
-
- QPointer<QObject> object;
-
-Q_SIGNALS:
- void modelDataChanged();
-};
-
-class VDMObjectDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- int propertyOffset;
- int signalOffset;
- bool shared;
- QMetaObjectBuilder builder;
-
- VDMObjectDelegateDataType()
- : propertyOffset(0)
- , signalOffset(0)
- , shared(true)
- {
- }
-
- VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- , propertyOffset(type.propertyOffset)
- , signalOffset(type.signalOffset)
- , shared(false)
- , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
- | QMetaObjectBuilder::Signals
- | QMetaObjectBuilder::SuperClass
- | QMetaObjectBuilder::ClassName)
- {
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- if (QObject *object = model.list.at(index).value<QObject *>())
- return object->property(role.toUtf8());
- return QVariant();
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return index >= 0 && index < model.list.count()
- ? new QQmlDMObjectData(metaType, dataType, index, row, column, qvariant_cast<QObject *>(model.list.at(index)))
- : nullptr;
- }
-
- void initializeMetaType(QQmlAdaptorModel &model)
- {
- Q_UNUSED(model);
- setModelDataType<QQmlDMObjectData>(&builder, this);
-
- metaObject.reset(builder.toMetaObject());
- // Note: ATM we cannot create a shared property cache for this class, since each model
- // object can have different properties. And to make those properties available to the
- // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass
- // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache.
- // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem
- // will always be available to the delegate, regardless of the import version.
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMObjectDelegateDataType *>(this)->release();
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
- QObject *updatedModelData = qvariant_cast<QObject *>(model.list.at(objectModelItem->index));
- objectModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
-{
-public:
- QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
- : m_data(data)
- , m_type(type)
- {
- QObjectPrivate *op = QObjectPrivate::get(m_data);
- *static_cast<QMetaObject *>(this) = *type->metaObject;
- op->metaObject = this;
- m_type->addref();
- }
-
- ~QQmlDMObjectDataMetaObject()
- {
- m_type->release();
- }
-
- int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
- {
- Q_ASSERT(o == m_data);
- Q_UNUSED(o);
-
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
- if (id >= m_type->propertyOffset
- && (call == QMetaObject::ReadProperty
- || call == QMetaObject::WriteProperty
- || call == QMetaObject::ResetProperty)) {
- if (m_data->object)
- QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
- return -1;
- } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
- QMetaObject::activate(m_data, this, id - m_type->signalOffset, nullptr);
- return -1;
- } else {
- return m_data->qt_metacall(call, id, arguments);
- }
- }
-
- int createProperty(const char *name, const char *) override
- {
- if (!m_data->object)
- return -1;
- const QMetaObject *metaObject = m_data->object->metaObject();
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
-
- const int previousPropertyCount = propertyCount() - propertyOffset();
- int propertyIndex = metaObject->indexOfProperty(name);
- if (propertyIndex == -1)
- return -1;
- if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
-
- if (m_type->shared) {
- VDMObjectDelegateDataType *type = m_type;
- m_type = new VDMObjectDelegateDataType(*m_type);
- type->release();
- }
-
- const int previousMethodCount = methodCount();
- int notifierId = previousMethodCount - methodOffset();
- for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
- QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
- QMetaPropertyBuilder propertyBuilder;
- if (property.hasNotifySignal()) {
- m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
- ++notifierId;
- } else {
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
- }
- propertyBuilder.setWritable(property.isWritable());
- propertyBuilder.setResettable(property.isResettable());
- propertyBuilder.setConstant(property.isConstant());
- }
-
- m_type->metaObject.reset(m_type->builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *m_type->metaObject;
-
- notifierId = previousMethodCount;
- for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
- QMetaProperty property = metaObject->property(i + objectPropertyOffset);
- if (property.hasNotifySignal()) {
- QQmlPropertyPrivate::connect(
- m_data->object, property.notifySignalIndex(), m_data, notifierId);
- ++notifierId;
- }
- }
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
- }
-
- QQmlDMObjectData *m_data;
- VDMObjectDelegateDataType *m_type;
-};
-
-QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , object(object)
-{
- new QQmlDMObjectDataMetaObject(this, dataType);
-}
-
-//-----------------------------------------------------------------
-// QQmlAdaptorModel
-//-----------------------------------------------------------------
-
-static const QQmlAdaptorModel::Accessors qt_vdm_null_accessors;
-
-QQmlAdaptorModel::Accessors::~Accessors()
-{
-}
-
-QQmlAdaptorModel::QQmlAdaptorModel()
- : accessors(&qt_vdm_null_accessors)
-{
-}
-
-QQmlAdaptorModel::~QQmlAdaptorModel()
-{
- accessors->cleanup(*this);
-}
-
-void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine)
-{
- accessors->cleanup(*this);
-
- list.setList(variant, engine);
-
- if (QObject *object = qvariant_cast<QObject *>(list.list())) {
- setObject(object, parent);
- if (qobject_cast<QAbstractItemModel *>(object))
- accessors = new VDMAbstractItemModelDataType(this);
- else
- accessors = new VDMObjectDelegateDataType;
- } else if (list.type() == QQmlListAccessor::ListProperty) {
- setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), parent);
- accessors = new VDMObjectDelegateDataType;
- } else if (list.type() != QQmlListAccessor::Invalid
- && list.type() != QQmlListAccessor::Instance) { // Null QObject
- setObject(nullptr, parent);
- accessors = new VDMListDelegateDataType;
- } else {
- setObject(nullptr, parent);
- accessors = &qt_vdm_null_accessors;
- }
-}
-
-void QQmlAdaptorModel::invalidateModel()
-{
- accessors->cleanup(*this);
- accessors = &qt_vdm_null_accessors;
- // Don't clear the model object as we still need the guard to clear the list variant if the
- // object is destroyed.
-}
-
-bool QQmlAdaptorModel::isValid() const
-{
- return accessors != &qt_vdm_null_accessors;
-}
-
-int QQmlAdaptorModel::count() const
-{
- return rowCount() * columnCount();
-}
-
-int QQmlAdaptorModel::rowCount() const
-{
- return qMax(0, accessors->rowCount(*this));
-}
-
-int QQmlAdaptorModel::columnCount() const
-{
- return qMax(0, accessors->columnCount(*this));
-}
-
-int QQmlAdaptorModel::rowAt(int index) const
-{
- int count = rowCount();
- return count <= 0 ? -1 : index % count;
-}
-
-int QQmlAdaptorModel::columnAt(int index) const
-{
- int count = rowCount();
- return count <= 0 ? -1 : index / count;
-}
-
-int QQmlAdaptorModel::indexAt(int row, int column) const
-{
- return column * rowCount() + row;
-}
-
-void QQmlAdaptorModel::useImportVersion(int minorVersion)
-{
- modelItemRevision = minorVersion;
-}
-
-void QQmlAdaptorModel::objectDestroyed(QObject *)
-{
- setModel(QVariant(), nullptr, nullptr);
-}
-
-QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4)
- : v4(v4)
-{
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("modelData"),
- QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
- listItemProto.set(v4, proto);
-}
-
-QQmlAdaptorModelEngineData::~QQmlAdaptorModelEngineData()
-{
-}
-
-QT_END_NAMESPACE
-
-#include <qqmladaptormodel.moc>
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
deleted file mode 100644
index 8c18466ab5..0000000000
--- a/src/qml/util/qqmladaptormodel_p.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLADAPTORMODEL_P_H
-#define QQMLADAPTORMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qabstractitemmodel.h>
-
-#include "private/qqmllistaccessor_p.h"
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlguard_p.h>
-#include <private/qqmlnullablevalue_p.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-class QQmlDelegateModel;
-class QQmlDelegateModelItem;
-class QQmlDelegateModelItemMetaType;
-
-class Q_QML_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
-{
-public:
- class Accessors
- {
- public:
- inline Accessors() {}
- virtual ~Accessors();
- virtual int rowCount(const QQmlAdaptorModel &) const { return 0; }
- virtual int columnCount(const QQmlAdaptorModel &) const { return 0; }
- virtual void cleanup(QQmlAdaptorModel &) const {}
-
- virtual QVariant value(const QQmlAdaptorModel &, int, const QString &) const {
- return QVariant(); }
-
- virtual QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &,
- QQmlDelegateModelItemMetaType *,
- int, int, int) const { return nullptr; }
-
- virtual bool notify(
- const QQmlAdaptorModel &,
- const QList<QQmlDelegateModelItem *> &,
- int,
- int,
- const QVector<int> &) const { return false; }
- virtual void replaceWatchedRoles(
- QQmlAdaptorModel &,
- const QList<QByteArray> &,
- const QList<QByteArray> &) const {}
- virtual QVariant parentModelIndex(const QQmlAdaptorModel &) const {
- return QVariant(); }
- virtual QVariant modelIndex(const QQmlAdaptorModel &, int) const {
- return QVariant(); }
- virtual bool canFetchMore(const QQmlAdaptorModel &) const { return false; }
- virtual void fetchMore(QQmlAdaptorModel &) const {}
-
- QScopedPointer<QMetaObject, QScopedPointerPodDeleter> metaObject;
- QQmlRefPointer<QQmlPropertyCache> propertyCache;
- };
-
- const Accessors *accessors;
- QPersistentModelIndex rootIndex;
- QQmlListAccessor list;
-
- int modelItemRevision = 0;
-
- QQmlAdaptorModel();
- ~QQmlAdaptorModel();
-
- inline QVariant model() const { return list.list(); }
- void setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine);
- void invalidateModel();
-
- bool isValid() const;
- int count() const;
- int rowCount() const;
- int columnCount() const;
- int rowAt(int index) const;
- int columnAt(int index) const;
- int indexAt(int row, int column) const;
-
- void useImportVersion(int minorVersion);
-
- inline bool adaptsAim() const { return qobject_cast<QAbstractItemModel *>(object()); }
- inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); }
- inline const QAbstractItemModel *aim() const { return static_cast<const QAbstractItemModel *>(object()); }
-
- inline QVariant value(int index, const QString &role) const {
- return accessors->value(*this, index, role); }
- inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) {
- return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); }
- inline bool hasProxyObject() const {
- return list.type() == QQmlListAccessor::Instance || list.type() == QQmlListAccessor::ListProperty; }
-
- inline bool notify(
- const QList<QQmlDelegateModelItem *> &items,
- int index,
- int count,
- const QVector<int> &roles) const {
- return accessors->notify(*this, items, index, count, roles); }
- inline void replaceWatchedRoles(
- const QList<QByteArray> &oldRoles, const QList<QByteArray> &newRoles) {
- accessors->replaceWatchedRoles(*this, oldRoles, newRoles); }
-
- inline QVariant modelIndex(int index) const { return accessors->modelIndex(*this, index); }
- inline QVariant parentModelIndex() const { return accessors->parentModelIndex(*this); }
- inline bool canFetchMore() const { return accessors->canFetchMore(*this); }
- inline void fetchMore() { return accessors->fetchMore(*this); }
-
-protected:
- void objectDestroyed(QObject *) override;
-};
-
-class QQmlAdaptorModelProxyInterface
-{
-public:
- virtual ~QQmlAdaptorModelProxyInterface() {}
-
- virtual QObject *proxiedObject() = 0;
-};
-
-#define QQmlAdaptorModelProxyInterface_iid "org.qt-project.Qt.QQmlAdaptorModelProxyInterface"
-
-Q_DECLARE_INTERFACE(QQmlAdaptorModelProxyInterface, QQmlAdaptorModelProxyInterface_iid)
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qml/util/qqmlchangeset.cpp
deleted file mode 100644
index ba876b42e2..0000000000
--- a/src/qml/util/qqmlchangeset.cpp
+++ /dev/null
@@ -1,583 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlchangeset_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QQmlChangeSet
- \brief The QQmlChangeSet class stores an ordered list of notifications about
- changes to a linear data set.
- \internal
-
- QQmlChangeSet can be used to record a series of notifications about items in an indexed list
- being inserted, removed, moved, and changed. Notifications in the set are re-ordered so that
- all notifications of a single type are grouped together and sorted in order of ascending index,
- with remove notifications preceding all others, followed by insert notification, and then
- change notifications.
-
- Moves in a change set are represented by a remove notification paired with an insert
- notification by way of a shared unique moveId. Re-ordering may result in one or both of the
- paired notifications being divided, when this happens the offset member of the notification
- will indicate the relative offset of the divided notification from the beginning of the
- original.
-*/
-
-/*!
- Constructs an empty change set.
-*/
-
-QQmlChangeSet::QQmlChangeSet()
- : m_difference(0)
-{
-}
-
-/*!
- Constructs a copy of a \a changeSet.
-*/
-
-QQmlChangeSet::QQmlChangeSet(const QQmlChangeSet &changeSet)
- : m_removes(changeSet.m_removes)
- , m_inserts(changeSet.m_inserts)
- , m_changes(changeSet.m_changes)
- , m_difference(changeSet.m_difference)
-{
-}
-
-/*!
- Destroys a change set.
-*/
-
-QQmlChangeSet::~QQmlChangeSet()
-{
-}
-
-/*!
- Assigns the value of a \a changeSet to another.
-*/
-
-QQmlChangeSet &QQmlChangeSet::operator =(const QQmlChangeSet &changeSet)
-{
- m_removes = changeSet.m_removes;
- m_inserts = changeSet.m_inserts;
- m_changes = changeSet.m_changes;
- m_difference = changeSet.m_difference;
- return *this;
-}
-
-/*!
- Appends a notification that \a count items were inserted at \a index.
-*/
-
-void QQmlChangeSet::insert(int index, int count)
-{
- insert(QVector<Change>() << Change(index, count));
-}
-
-/*!
- Appends a notification that \a count items were removed at \a index.
-*/
-
-void QQmlChangeSet::remove(int index, int count)
-{
- QVector<Change> removes;
- removes.append(Change(index, count));
- remove(&removes, nullptr);
-}
-
-/*!
- Appends a notification that \a count items were moved \a from one index \a to another.
-
- The \a moveId must be unique across the lifetime of the change set and any related
- change sets.
-*/
-
-void QQmlChangeSet::move(int from, int to, int count, int moveId)
-{
- QVector<Change> removes;
- removes.append(Change(from, count, moveId));
- QVector<Change> inserts;
- inserts.append(Change(to, count, moveId));
- remove(&removes, &inserts);
- insert(inserts);
-}
-
-/*!
- Appends a notification that \a count items were changed at \a index.
-*/
-
-void QQmlChangeSet::change(int index, int count)
-{
- QVector<Change> changes;
- changes.append(Change(index, count));
- change(changes);
-}
-
-/*!
- Applies the changes in a \a changeSet to another.
-*/
-
-void QQmlChangeSet::apply(const QQmlChangeSet &changeSet)
-{
- QVector<Change> r = changeSet.m_removes;
- QVector<Change> i = changeSet.m_inserts;
- QVector<Change> c = changeSet.m_changes;
- remove(&r, &i);
- insert(i);
- change(c);
-}
-
-/*!
- Applies a list of \a removes to a change set.
-
- If a remove contains a moveId then any intersecting insert in the set will replace the
- corresponding intersection in the optional \a inserts list.
-*/
-
-void QQmlChangeSet::remove(const QVector<Change> &removes, QVector<Change> *inserts)
-{
- QVector<Change> r = removes;
- remove(&r, inserts);
-}
-
-void QQmlChangeSet::remove(QVector<Change> *removes, QVector<Change> *inserts)
-{
- int removeCount = 0;
- int insertCount = 0;
- QVector<Change>::iterator insert = m_inserts.begin();
- QVector<Change>::iterator change = m_changes.begin();
- QVector<Change>::iterator rit = removes->begin();
- for (; rit != removes->end(); ++rit) {
- int index = rit->index + removeCount;
- int count = rit->count;
-
- // Decrement the accumulated remove count from the indexes of any changes prior to the
- // current remove.
- for (; change != m_changes.end() && change->end() < rit->index; ++change)
- change->index -= removeCount;
- // Remove any portion of a change notification that intersects the current remove.
- for (; change != m_changes.end() && change->index > rit->end(); ++change) {
- change->count -= qMin(change->end(), rit->end()) - qMax(change->index, rit->index);
- if (change->count == 0) {
- change = m_changes.erase(change);
- } else if (rit->index < change->index) {
- change->index = rit->index;
- }
- }
-
- // Decrement the accumulated remove count from the indexes of any inserts prior to the
- // current remove.
- for (; insert != m_inserts.end() && insert->end() <= index; ++insert) {
- insertCount += insert->count;
- insert->index -= removeCount;
- }
-
- rit->index -= insertCount;
-
- // Remove any portion of a insert notification that intersects the current remove.
- while (insert != m_inserts.end() && insert->index < index + count) {
- int offset = index - insert->index;
- const int difference = qMin(insert->end(), index + count) - qMax(insert->index, index);
-
- // If part of the remove or insert that precedes the intersection has a moveId create
- // a new delta for that portion and subtract the size of that delta from the current
- // one.
- if (offset < 0 && rit->moveId != -1) {
- rit = removes->insert(rit, Change(
- rit->index, -offset, rit->moveId, rit->offset));
- ++rit;
- rit->count -= -offset;
- rit->offset += -offset;
- index += -offset;
- count -= -offset;
- removeCount += -offset;
- offset = 0;
- } else if (offset > 0 && insert->moveId != -1) {
- insert = m_inserts.insert(insert, Change(
- insert->index - removeCount, offset, insert->moveId, insert->offset));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- insert->offset += offset;
- rit->index -= offset;
- insertCount += offset;
- }
-
- // If the current remove has a move id, find any inserts with the same move id and
- // replace the corresponding sections with the insert removed from the change set.
- if (rit->moveId != -1 && difference > 0 && inserts) {
- for (QVector<Change>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) {
- if (iit->moveId != rit->moveId
- || rit->offset > iit->offset + iit->count
- || iit->offset > rit->offset + difference) {
- continue;
- }
- // If the intersecting insert starts before the replacement one create
- // a new insert for the portion prior to the replacement insert.
- const int overlapOffset = rit->offset - iit->offset;
- if (overlapOffset > 0) {
- iit = inserts->insert(iit, Change(
- iit->index, overlapOffset, iit->moveId, iit->offset));
- ++iit;
- iit->index += overlapOffset;
- iit->count -= overlapOffset;
- iit->offset += overlapOffset;
- }
- if (iit->offset >= rit->offset
- && iit->offset + iit->count <= rit->offset + difference) {
- // If the replacement insert completely encapsulates the existing
- // one just change the moveId.
- iit->moveId = insert->moveId;
- iit->offset = insert->offset + qMax(0, -overlapOffset);
- } else {
- // Create a new insertion before the intersecting one with the number of intersecting
- // items and remove that number from that insert.
- const int count
- = qMin(iit->offset + iit->count, rit->offset + difference)
- - qMax(iit->offset, rit->offset);
- iit = inserts->insert(iit, Change(
- iit->index,
- count,
- insert->moveId,
- insert->offset + qMax(0, -overlapOffset)));
- ++iit;
- iit->index += count;
- iit->count -= count;
- iit->offset += count;
- }
- }
- }
-
- // Subtract the number of intersecting items from the current remove and insert.
- insert->count -= difference;
- insert->offset += difference;
- rit->count -= difference;
- rit->offset += difference;
-
- index += difference;
- count -= difference;
- removeCount += difference;
-
- if (insert->count == 0) {
- insert = m_inserts.erase(insert);
- } else if (rit->count == -offset || rit->count == 0) {
- insert->index += difference;
- break;
- } else {
- insert->index -= removeCount - difference;
- rit->index -= insert->count;
- insertCount += insert->count;
- ++insert;
- }
- }
- removeCount += rit->count;
- }
- for (; insert != m_inserts.end(); ++insert)
- insert->index -= removeCount;
-
- removeCount = 0;
- QVector<Change>::iterator remove = m_removes.begin();
- for (rit = removes->begin(); rit != removes->end(); ++rit) {
- if (rit->count == 0)
- continue;
- // Accumulate consecutive removes into a single delta before attempting to apply.
- for (QVector<Change>::iterator next = rit + 1; next != removes->end()
- && next->index == rit->index
- && next->moveId == -1
- && rit->moveId == -1; ++next) {
- next->count += rit->count;
- rit = next;
- }
- int index = rit->index + removeCount;
- // Decrement the accumulated remove count from the indexes of any inserts prior to the
- // current remove.
- for (; remove != m_removes.end() && index > remove->index; ++remove)
- remove->index -= removeCount;
- while (remove != m_removes.end() && index + rit->count >= remove->index) {
- int count = 0;
- const int offset = remove->index - index;
- QVector<Change>::iterator rend = remove;
- for (; rend != m_removes.end()
- && rit->moveId == -1
- && rend->moveId == -1
- && index + rit->count >= rend->index; ++rend) {
- count += rend->count;
- }
- if (remove != rend) {
- // Accumulate all existing non-move removes that are encapsulated by or immediately
- // follow the current remove into it.
- int difference = 0;
- if (rend == m_removes.end()) {
- difference = rit->count;
- } else if (rit->index + rit->count < rend->index - removeCount) {
- difference = rit->count;
- } else if (rend->moveId != -1) {
- difference = rend->index - removeCount - rit->index;
- index += difference;
- }
- count += difference;
-
- rit->count -= difference;
- removeCount += difference;
- remove->index = rit->index;
- remove->count = count;
- remove = m_removes.erase(++remove, rend);
- } else {
- // Insert a remove for the portion of the unmergable current remove prior to the
- // point of intersection.
- if (offset > 0) {
- remove = m_removes.insert(remove, Change(
- rit->index, offset, rit->moveId, rit->offset));
- ++remove;
- rit->count -= offset;
- rit->offset += offset;
- removeCount += offset;
- index += offset;
- }
- remove->index = rit->index;
-
- ++remove;
- }
- }
-
- if (rit->count > 0) {
- remove = m_removes.insert(remove, *rit);
- ++remove;
- }
- removeCount += rit->count;
- }
- for (; remove != m_removes.end(); ++remove)
- remove->index -= removeCount;
- m_difference -= removeCount;
-}
-
-/*!
- Applies a list of \a inserts to a change set.
-*/
-
-void QQmlChangeSet::insert(const QVector<Change> &inserts)
-{
- int insertCount = 0;
- QVector<Change>::iterator insert = m_inserts.begin();
- QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Change>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) {
- if (iit->count == 0)
- continue;
- int index = iit->index - insertCount;
-
- Change current = *iit;
- // Accumulate consecutive inserts into a single delta before attempting to insert.
- for (QVector<Change>::const_iterator next = iit + 1; next != inserts.end()
- && next->index == iit->index + iit->count
- && next->moveId == -1
- && iit->moveId == -1; ++next) {
- current.count += next->count;
- iit = next;
- }
-
- // Increment the index of any changes before the current insert by the accumlated insert
- // count.
- for (; change != m_changes.end() && change->index >= index; ++change)
- change->index += insertCount;
- // If the current insert index is in the middle of a change split it in two at that
- // point and increment the index of the latter half.
- if (change != m_changes.end() && change->index < index + iit->count) {
- int offset = index - change->index;
- change = m_changes.insert(change, Change(change->index + insertCount, offset));
- ++change;
- change->index += iit->count + offset;
- change->count -= offset;
- }
-
- // Increment the index of any inserts before the current insert by the accumlated insert
- // count.
- for (; insert != m_inserts.end() && index > insert->index + insert->count; ++insert)
- insert->index += insertCount;
- if (insert == m_inserts.end()) {
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else {
- const int offset = index - insert->index;
-
- if (offset < 0) {
- // If the current insert is before an existing insert and not adjacent just insert
- // it into the list.
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else if (iit->moveId == -1 && insert->moveId == -1) {
- // If neither the current nor existing insert has a moveId add the current insert
- // to the existing one.
- if (offset < insert->count) {
- insert->index -= current.count;
- insert->count += current.count;
- } else {
- insert->index += insertCount;
- insert->count += current.count;
- ++insert;
- }
- } else if (offset < insert->count) {
- // If either insert has a moveId then split the existing insert and insert the
- // current one in the middle.
- if (offset > 0) {
- insert = m_inserts.insert(insert, Change(
- insert->index + insertCount, offset, insert->moveId, insert->offset));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- insert->offset += offset;
- }
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else {
- insert->index += insertCount;
- ++insert;
- insert = m_inserts.insert(insert, current);
- ++insert;
- }
- }
- insertCount += current.count;
- }
- for (; insert != m_inserts.end(); ++insert)
- insert->index += insertCount;
- m_difference += insertCount;
-}
-
-/*!
- Applies a combined list of \a removes and \a inserts to a change set. This is equivalent
- calling \l remove() followed by \l insert() with the same lists.
-*/
-
-void QQmlChangeSet::move(const QVector<Change> &removes, const QVector<Change> &inserts)
-{
- QVector<Change> r = removes;
- QVector<Change> i = inserts;
- remove(&r, &i);
- insert(i);
-}
-
-/*!
- Applies a list of \a changes to a change set.
-*/
-
-void QQmlChangeSet::change(const QVector<Change> &changes)
-{
- QVector<Change> c = changes;
- change(&c);
-}
-
-void QQmlChangeSet::change(QVector<Change> *changes)
-{
- QVector<Change>::iterator insert = m_inserts.begin();
- QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Change>::iterator cit = changes->begin(); cit != changes->end(); ++cit) {
- for (; insert != m_inserts.end() && insert->end() < cit->index; ++insert) {}
- for (; insert != m_inserts.end() && insert->index < cit->end(); ++insert) {
- const int offset = insert->index - cit->index;
- const int count = cit->count + cit->index - insert->index - insert->count;
- if (offset == 0) {
- cit->index = insert->index + insert->count;
- cit->count = count;
- } else {
- cit = changes->insert(++cit, Change(insert->index + insert->count, count));
- --cit;
- cit->count = offset;
- }
- }
-
- for (; change != m_changes.end() && change->index + change->count < cit->index; ++change) {}
- if (change == m_changes.end() || change->index > cit->index + cit->count) {
- if (cit->count > 0) {
- change = m_changes.insert(change, *cit);
- ++change;
- }
- } else {
- if (cit->index < change->index) {
- change->count += change->index - cit->index;
- change->index = cit->index;
- }
-
- if (cit->index + cit->count > change->index + change->count) {
- change->count = cit->index + cit->count - change->index;
- QVector<Change>::iterator cbegin = change;
- QVector<Change>::iterator cend = ++cbegin;
- for (; cend != m_changes.end() && cend->index <= change->index + change->count; ++cend) {
- if (cend->index + cend->count > change->index + change->count)
- change->count = cend->index + cend->count - change->index;
- }
- if (cbegin != cend) {
- change = m_changes.erase(cbegin, cend);
- --change;
- }
- }
- }
- }
-}
-
-/*!
- Prints the contents of a change \a set to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
-{
- debug.nospace() << "QQmlChangeSet(";
- const QVector<QQmlChangeSet::Change> &removes = set.removes();
- for (const QQmlChangeSet::Change &remove : removes)
- debug << remove;
- const QVector<QQmlChangeSet::Change> &inserts = set.inserts();
- for (const QQmlChangeSet::Change &insert : inserts)
- debug << insert;
- const QVector<QQmlChangeSet::Change> &changes = set.changes();
- for (const QQmlChangeSet::Change &change : changes)
- debug << change;
- return debug.nospace() << ')';
-}
-
-/*!
- Prints a \a change to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change)
-{
- return (debug.nospace() << "Change(" << change.index << ',' << change.count << ')').space();
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qml/util/qqmlchangeset_p.h
deleted file mode 100644
index 8347a3ff19..0000000000
--- a/src/qml/util/qqmlchangeset_p.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLCHANGESET_P_H
-#define QQMLCHANGESET_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qvector.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_PRIVATE_EXPORT QQmlChangeSet
-{
-public:
- struct MoveKey
- {
- MoveKey() {}
- MoveKey(int moveId, int offset) : moveId(moveId), offset(offset) {}
- int moveId = -1;
- int offset = 0;
- };
-
- // The storrage for Change (below). This struct is trivial, which it has to be in order to store
- // it in a QV4::Heap::Base object. The Change struct doesn't add any storage fields, so it is
- // safe to cast ChangeData to/from Change.
- struct ChangeData
- {
- int index;
- int count;
- int moveId;
- int offset;
- };
-
- struct Change: ChangeData
- {
- Change() {
- index = 0;
- count = 0;
- moveId = -1;
- offset = 0;
- }
- Change(int index, int count, int moveId = -1, int offset = 0) {
- this->index = index;
- this->count = count;
- this->moveId = moveId;
- this->offset = offset;
- }
-
- bool isMove() const { return moveId >= 0; }
-
- MoveKey moveKey(int index) const {
- return MoveKey(moveId, index - Change::index + offset); }
-
- int start() const { return index; }
- int end() const { return index + count; }
- };
-
- QQmlChangeSet();
- QQmlChangeSet(const QQmlChangeSet &changeSet);
- ~QQmlChangeSet();
-
- QQmlChangeSet &operator =(const QQmlChangeSet &changeSet);
-
- const QVector<Change> &removes() const { return m_removes; }
- const QVector<Change> &inserts() const { return m_inserts; }
- const QVector<Change> &changes() const { return m_changes; }
-
- void insert(int index, int count);
- void remove(int index, int count);
- void move(int from, int to, int count, int moveId);
- void change(int index, int count);
-
- void insert(const QVector<Change> &inserts);
- void remove(const QVector<Change> &removes, QVector<Change> *inserts = nullptr);
- void move(const QVector<Change> &removes, const QVector<Change> &inserts);
- void change(const QVector<Change> &changes);
- void apply(const QQmlChangeSet &changeSet);
-
- bool isEmpty() const { return m_removes.empty() && m_inserts.empty() && m_changes.isEmpty(); }
-
- void clear()
- {
- m_removes.clear();
- m_inserts.clear();
- m_changes.clear();
- m_difference = 0;
- }
-
- int difference() const { return m_difference; }
-
-private:
- void remove(QVector<Change> *removes, QVector<Change> *inserts);
- void change(QVector<Change> *changes);
-
- QVector<Change> m_removes;
- QVector<Change> m_inserts;
- QVector<Change> m_changes;
- int m_difference;
-};
-
-Q_DECLARE_TYPEINFO(QQmlChangeSet::Change, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlChangeSet::MoveKey, Q_PRIMITIVE_TYPE);
-
-inline uint qHash(const QQmlChangeSet::MoveKey &key) { return qHash(qMakePair(key.moveId, key.offset)); }
-inline bool operator ==(const QQmlChangeSet::MoveKey &l, const QQmlChangeSet::MoveKey &r) {
- return l.moveId == r.moveId && l.offset == r.offset; }
-
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/qqmllistaccessor.cpp b/src/qml/util/qqmllistaccessor.cpp
deleted file mode 100644
index 46a11e2bc2..0000000000
--- a/src/qml/util/qqmllistaccessor.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistaccessor_p.h"
-
-#include <private/qqmlmetatype_p.h>
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qdebug.h>
-
-// ### Remove me
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlListAccessor::QQmlListAccessor()
-: m_type(Invalid)
-{
-}
-
-QQmlListAccessor::~QQmlListAccessor()
-{
-}
-
-QVariant QQmlListAccessor::list() const
-{
- return d;
-}
-
-void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
-{
- d = v;
-
- // An incoming JS array as model is treated as a variant list, so we need to
- // convert it first with toVariant().
- if (d.userType() == qMetaTypeId<QJSValue>())
- d = d.value<QJSValue>().toVariant();
-
- QQmlEnginePrivate *enginePrivate = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- if (!d.isValid()) {
- m_type = Invalid;
- } else if (d.userType() == QVariant::StringList) {
- m_type = StringList;
- } else if (d.userType() == QMetaType::QVariantList) {
- m_type = VariantList;
- } else if (d.canConvert(QVariant::Int)) {
- // Here we have to check for an upper limit, because down the line code might (well, will)
- // allocate memory depending on the number of elements. The upper limit cannot be INT_MAX:
- // QVector<QPointer<QQuickItem>> something;
- // something.resize(count());
- // (See e.g. QQuickRepeater::regenerate())
- // This will allocate data along the lines of:
- // sizeof(QPointer<QQuickItem>) * count() + QVector::headerSize
- // So, doing an approximate round-down-to-nice-number, we get:
- const int upperLimit = 100 * 1000 * 1000;
-
- int i = v.toInt();
- if (i < 0) {
- qWarning("Model size of %d is less than 0", i);
- m_type = Invalid;
- } else if (i > upperLimit) {
- qWarning("Model size of %d is bigger than the upper limit %d", i, upperLimit);
- m_type = Invalid;
- } else {
- m_type = Integer;
- }
- } else if ((!enginePrivate && QQmlMetaType::isQObject(d.userType())) ||
- (enginePrivate && enginePrivate->isQObject(d.userType()))) {
- QObject *data = enginePrivate?enginePrivate->toQObject(d):QQmlMetaType::toQObject(d);
- d = QVariant::fromValue(data);
- m_type = Instance;
- } else if (d.userType() == qMetaTypeId<QQmlListReference>()) {
- m_type = ListProperty;
- } else {
- m_type = Instance;
- }
-}
-
-int QQmlListAccessor::count() const
-{
- switch(m_type) {
- case StringList:
- return qvariant_cast<QStringList>(d).count();
- case VariantList:
- return qvariant_cast<QVariantList>(d).count();
- case ListProperty:
- return ((const QQmlListReference *)d.constData())->count();
- case Instance:
- return 1;
- case Integer:
- return d.toInt();
- default:
- case Invalid:
- return 0;
- }
-}
-
-QVariant QQmlListAccessor::at(int idx) const
-{
- Q_ASSERT(idx >= 0 && idx < count());
- switch(m_type) {
- case StringList:
- return QVariant::fromValue(qvariant_cast<QStringList>(d).at(idx));
- case VariantList:
- return qvariant_cast<QVariantList>(d).at(idx);
- case ListProperty:
- return QVariant::fromValue(((const QQmlListReference *)d.constData())->at(idx));
- case Instance:
- return d;
- case Integer:
- return QVariant(idx);
- default:
- case Invalid:
- return QVariant();
- }
-}
-
-bool QQmlListAccessor::isValid() const
-{
- return m_type != Invalid;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/util/qqmllistaccessor_p.h b/src/qml/util/qqmllistaccessor_p.h
deleted file mode 100644
index bcd079adef..0000000000
--- a/src/qml/util/qqmllistaccessor_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTACCESSOR_H
-#define QQMLLISTACCESSOR_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QVariant>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-class Q_AUTOTEST_EXPORT QQmlListAccessor
-{
-public:
- QQmlListAccessor();
- ~QQmlListAccessor();
-
- QVariant list() const;
- void setList(const QVariant &, QQmlEngine * = nullptr);
-
- bool isValid() const;
-
- int count() const;
- QVariant at(int) const;
-
- enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer };
- Type type() const { return m_type; }
-
-private:
- Type m_type;
- QVariant d;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLLISTACCESSOR_H
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp
deleted file mode 100644
index 921e86f355..0000000000
--- a/src/qml/util/qqmllistcompositor.cpp
+++ /dev/null
@@ -1,1482 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistcompositor_p.h"
-
-#include <QtCore/qvarlengtharray.h>
-
-//#define QT_QML_VERIFY_MINIMAL
-//#define QT_QML_VERIFY_INTEGRITY
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QQmlListCompositor
- \brief The QQmlListCompositor class provides a lookup table for filtered, or re-ordered list
- indexes.
- \internal
-
- QQmlListCompositor is intended as an aid for developing proxy models. It doesn't however
- directly proxy a list or model, instead a range of indexes from one or many lists can be
- inserted into the compositor and then categorized and shuffled around and it will manage the
- task of translating from an index in the combined space into an index in a particular list.
-
- Within a compositor indexes are categorized into groups where a group is a sub-set of the
- total indexes referenced by the compositor, each with an address space ranging from 0 to
- the number of indexes in the group - 1. Group memberships are independent of each other with
- the one exception that items always retain the same order so if an index is moved within a
- group, its position in other groups will change as well.
-
- The iterator classes encapsulate information about a specific position in a compositor group.
- This includes a source list, the index of an item within that list and the groups that item
- is a member of. The iterator for a specific position in a group can be retrieved with the
- find() function and the addition and subtraction operators of the iterators can be used to
- navigate to adjacent items in the same group.
-
- Items can be added to the compositor with the append() and insert() functions, group
- membership can be changed with the setFlags() and clearFlags() functions, and the position
- of items in the compositor can be changed with the move() function. Each of these functions
- optionally returns a list of the changes made to indexes within each group which can then
- be propagated to view so that it can correctly refresh its contents; e.g. 3 items
- removed at index 6, and 5 items inserted at index 1. The notification changes are always
- ordered from the start of the list to the end and accumulate, so if 5 items are removed at
- index 4, one is skipped and then 3 move are removed, the changes returned are 5 items removed
- at index 4, followed by 3 items removed at index 4.
-
- When the contents of a source list change, the mappings within the compositor can be updated
- with the listItemsInserted(), listItemsRemoved(), listItemsMoved(), and listItemsChanged()
- functions. Like the direct manipulation functions these too return a list of group indexes
- affected by the change. If items are removed from a source list they are also removed from
- any groups they belong to with the one exception being items belonging to the \l Cache group.
- When items belonging to this group are removed the list, index, and other group membership
- information are discarded but Cache membership is retained until explicitly removed. This
- allows the cache index to be retained until cached resources for that item are actually
- released.
-
- Internally the index mapping is stored as a list of Range objects, each has a list identifier,
- a start index, a count, and a set of flags which represent group membership and some other
- properties. The group index of a range is the sum of all preceding ranges that are members of
- that group. To avoid the inefficiency of iterating over potentially all ranges when looking
- for a specific index, each time a lookup is done the range and its indexes are cached and the
- next lookup is done relative to this. This works out to near constant time in most relevant
- use cases because successive index lookups are most frequently adjacent. The total number of
- ranges is often quite small, which helps as well. If there is a need for faster random access
- then a skip list like index may be an appropriate addition.
-
- \sa DelegateModel
-*/
-
-#ifdef QT_QML_VERIFY_MINIMAL
-#define QT_QML_VERIFY_INTEGRITY
-/*
- Diagnostic to verify there are no consecutive ranges, or that the compositor contains the
- most compact representation possible.
-
- Returns false and prints a warning if any range has a starting index equal to the end
- (index + count) index of the previous range, and both ranges also have the same flags and list
- property.
-
- If there are no consecutive ranges this will return true.
-*/
-
-static bool qt_verifyMinimal(
- const QQmlListCompositor::iterator &begin,
- const QQmlListCompositor::iterator &end)
-{
- bool minimal = true;
- int index = 0;
-
- for (const QQmlListCompositor::Range *range = begin->next; range != *end; range = range->next, ++index) {
- if (range->previous->list == range->list
- && range->previous->flags == (range->flags & ~QQmlListCompositor::AppendFlag)
- && range->previous->end() == range->index) {
- qWarning() << index << "Consecutive ranges";
- qWarning() << *range->previous;
- qWarning() << *range;
- minimal = false;
- }
- }
-
- return minimal;
-}
-
-#endif
-
-#ifdef QT_QML_VERIFY_INTEGRITY
-static bool qt_printInfo(const QQmlListCompositor &compositor)
-{
- qWarning() << compositor;
- return true;
-}
-
-/*
- Diagnostic to verify the integrity of a compositor.
-
- Per range this verifies there are no invalid range combinations, that non-append ranges have
- positive non-zero counts, and that list ranges have non-negative indexes.
-
- Accumulatively this verifies that the cached total group counts match the sum of counts
- of member ranges.
-*/
-
-static bool qt_verifyIntegrity(
- const QQmlListCompositor::iterator &begin,
- const QQmlListCompositor::iterator &end,
- const QQmlListCompositor::iterator &cachedIt)
-{
- bool valid = true;
-
- int index = 0;
- QQmlListCompositor::iterator it;
- for (it = begin; *it != *end; *it = it->next) {
- if (it->count == 0 && !it->append()) {
- qWarning() << index << "Empty non-append range";
- valid = false;
- }
- if (it->count < 0) {
- qWarning() << index << "Negative count";
- valid = false;
- }
- if (it->list && it->flags != QQmlListCompositor::CacheFlag && it->index < 0) {
- qWarning() << index <<"Negative index";
- valid = false;
- }
- if (it->previous->next != it.range) {
- qWarning() << index << "broken list: it->previous->next != it.range";
- valid = false;
- }
- if (it->next->previous != it.range) {
- qWarning() << index << "broken list: it->next->previous != it.range";
- valid = false;
- }
- if (*it == *cachedIt) {
- for (int i = 0; i < end.groupCount; ++i) {
- int groupIndex = it.index[i];
- if (cachedIt->flags & (1 << i))
- groupIndex += cachedIt.offset;
- if (groupIndex != cachedIt.index[i]) {
- qWarning() << index
- << "invalid cached index"
- << QQmlListCompositor::Group(i)
- << "Expected:"
- << groupIndex
- << "Actual"
- << cachedIt.index[i]
- << cachedIt;
- valid = false;
- }
- }
- }
- it.incrementIndexes(it->count);
- ++index;
- }
-
- for (int i = 0; i < end.groupCount; ++i) {
- if (end.index[i] != it.index[i]) {
- qWarning() << "Group" << i << "count invalid. Expected:" << end.index[i] << "Actual:" << it.index[i];
- valid = false;
- }
- }
- return valid;
-}
-#endif
-
-#if defined(QT_QML_VERIFY_MINIMAL)
-# define QT_QML_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!(qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
- && qt_verifyMinimal(iterator(m_ranges.next, 0, Default, m_groupCount), m_end)) \
- && qt_printInfo(*this)));
-#elif defined(QT_QML_VERIFY_INTEGRITY)
-# define QT_QML_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
- && qt_printInfo(*this)));
-#else
-# define QT_QML_VERIFY_LISTCOMPOSITOR
-#endif
-
-//#define QT_QML_TRACE_LISTCOMPOSITOR(args) qDebug() << m_end.index[1] << m_end.index[0] << Q_FUNC_INFO args;
-#define QT_QML_TRACE_LISTCOMPOSITOR(args)
-
-QQmlListCompositor::iterator &QQmlListCompositor::iterator::operator +=(int difference)
-{
- // Update all indexes to the start of the range.
- decrementIndexes(offset);
-
- // If the iterator group isn't a member of the current range ignore the current offset.
- if (!(range->flags & groupFlag))
- offset = 0;
-
- offset += difference;
-
- // Iterate backwards looking for a range with a positive offset.
- while (offset <= 0 && range->previous->flags) {
- range = range->previous;
- if (range->flags & groupFlag)
- offset += range->count;
- decrementIndexes(range->count);
- }
-
- // Iterate forwards looking for the first range which contains both the offset and the
- // iterator group.
- while (range->flags && (offset >= range->count || !(range->flags & groupFlag))) {
- if (range->flags & groupFlag)
- offset -= range->count;
- incrementIndexes(range->count);
- range = range->next;
- }
-
- // Update all the indexes to inclue the remaining offset.
- incrementIndexes(offset);
-
- return *this;
-}
-
-QQmlListCompositor::insert_iterator &QQmlListCompositor::insert_iterator::operator +=(int difference)
-{
- iterator::operator +=(difference);
-
- // If the previous range contains the append flag move the iterator to the tail of the previous
- // range so that appended appear after the insert position.
- if (offset == 0 && range->previous->append()) {
- range = range->previous;
- offset = range->inGroup() ? range->count : 0;
- }
-
- return *this;
-}
-
-
-/*!
- Constructs an empty list compositor.
-*/
-
-QQmlListCompositor::QQmlListCompositor()
- : m_end(m_ranges.next, 0, Default, 2)
- , m_cacheIt(m_end)
- , m_groupCount(2)
- , m_defaultFlags(PrependFlag | DefaultFlag)
- , m_removeFlags(AppendFlag | PrependFlag | GroupMask)
- , m_moveId(0)
-{
-}
-
-/*!
- Destroys a list compositor.
-*/
-
-QQmlListCompositor::~QQmlListCompositor()
-{
- for (Range *next, *range = m_ranges.next; range != &m_ranges; range = next) {
- next = range->next;
- delete range;
- }
-}
-
-/*!
- Inserts a range with the given source \a list, start \a index, \a count and \a flags, in front
- of the existing range \a before.
-*/
-
-inline QQmlListCompositor::Range *QQmlListCompositor::insert(
- Range *before, void *list, int index, int count, uint flags)
-{
- return new Range(before, list, index, count, flags);
-}
-
-/*!
- Erases a \a range from the compositor.
-
- Returns a pointer to the next range in the compositor.
-*/
-
-inline QQmlListCompositor::Range *QQmlListCompositor::erase(
- Range *range)
-{
- Range *next = range->next;
- next->previous = range->previous;
- next->previous->next = range->next;
- delete range;
- return next;
-}
-
-/*!
- Sets the number (\a count) of possible groups that items may belong to in a compositor.
-*/
-
-void QQmlListCompositor::setGroupCount(int count)
-{
- m_groupCount = count;
- m_end = iterator(&m_ranges, 0, Default, m_groupCount);
- m_cacheIt = m_end;
-}
-
-/*!
- Returns the number of items that belong to a \a group.
-*/
-
-int QQmlListCompositor::count(Group group) const
-{
- return m_end.index[group];
-}
-
-/*!
- Returns an iterator representing the item at \a index in a \a group.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::find(Group group, int index)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index)
- Q_ASSERT(index >=0 && index < count(group));
- if (m_cacheIt == m_end) {
- m_cacheIt = iterator(m_ranges.next, 0, group, m_groupCount);
- m_cacheIt += index;
- } else {
- const int offset = index - m_cacheIt.index[group];
- m_cacheIt.setGroup(group);
- m_cacheIt += offset;
- }
- Q_ASSERT(m_cacheIt.index[group] == index);
- Q_ASSERT(m_cacheIt->inGroup(group));
- QT_QML_VERIFY_LISTCOMPOSITOR
- return m_cacheIt;
-}
-
-/*!
- Returns an iterator representing the item at \a index in a \a group.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::find(Group group, int index) const
-{
- return const_cast<QQmlListCompositor *>(this)->find(group, index);
-}
-
-/*!
- Returns an iterator representing an insert position in front of the item at \a index in a
- \a group.
-
- The iterator for an insert position can sometimes resolve to a different Range than a regular
- iterator. This is because when items are inserted on a boundary between Ranges, if the first
- range has the Append flag set then the items should be inserted into that range to ensure
- that the append position for the existing range remains after the insert position.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::insert_iterator QQmlListCompositor::findInsertPosition(Group group, int index)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index)
- Q_ASSERT(index >=0 && index <= count(group));
- insert_iterator it;
- if (m_cacheIt == m_end) {
- it = iterator(m_ranges.next, 0, group, m_groupCount);
- it += index;
- } else {
- const int offset = index - m_cacheIt.index[group];
- it = m_cacheIt;
- it.setGroup(group);
- it += offset;
- }
- Q_ASSERT(it.index[group] == index);
- return it;
-}
-
-/*!
- Appends a range of \a count indexes starting at \a index from a \a list into a compositor
- with the given \a flags.
-
- If supplied the \a inserts list will be populated with the positions of the inserted items
- in each group.
-*/
-
-void QQmlListCompositor::append(
- void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count << flags)
- insert(m_end, list, index, count, flags, inserts);
-}
-
-/*!
- Inserts a range of \a count indexes starting at \a index from a \a list with the given \a flags
- into a \a group at index \a before.
-
- If supplied the \a inserts list will be populated with the positions of items inserted into
- each group.
-*/
-
-void QQmlListCompositor::insert(
- Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << before << list << index << count << flags)
- insert(findInsertPosition(group, before), list, index, count, flags, inserts);
-}
-
-/*!
- Inserts a range of \a count indexes starting at \a index from a \a list with the given \a flags
- into a compositor at position \a before.
-
- If supplied the \a inserts list will be populated with the positions of items inserted into
- each group.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::insert(
- iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< before << list << index << count << flags)
- if (inserts) {
- inserts->append(Insert(before, count, flags & GroupMask));
- }
- if (before.offset > 0) {
- // Inserting into the middle of a range. Split it two and update the iterator so it's
- // positioned at the start of the second half.
- *before = insert(
- *before, before->list, before->index, before.offset, before->flags & ~AppendFlag)->next;
- before->index += before.offset;
- before->count -= before.offset;
- before.offset = 0;
- }
-
-
- if (!(flags & AppendFlag) && *before != m_ranges.next
- && before->previous->list == list
- && before->previous->flags == flags
- && (!list || before->previous->end() == index)) {
- // The insert arguments represent a continuation of the previous range so increment
- // its count instead of inserting a new range.
- before->previous->count += count;
- before.incrementIndexes(count, flags);
- } else {
- *before = insert(*before, list, index, count, flags);
- before.offset = 0;
- }
-
- if (!(flags & AppendFlag) && before->next != &m_ranges
- && before->list == before->next->list
- && before->flags == before->next->flags
- && (!list || before->end() == before->next->index)) {
- // The current range and the next are continuous so add their counts and delete one.
- before->next->index = before->index;
- before->next->count += before->count;
- *before = erase(*before);
- }
-
- m_end.incrementIndexes(count, flags);
- m_cacheIt = before;
- QT_QML_VERIFY_LISTCOMPOSITOR
- return before;
-}
-
-/*!
- Sets the given flags \a flags on \a count items belonging to \a group starting at the position
- identified by \a fromGroup and the index \a from.
-
- If supplied the \a inserts list will be populated with insert notifications for affected groups.
-*/
-
-void QQmlListCompositor::setFlags(
- Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
- setFlags(find(fromGroup, from), count, group, flags, inserts);
-}
-
-/*!
- Sets the given flags \a flags on \a count items belonging to \a group starting at the position
- \a from.
-
- If supplied the \a inserts list will be populated with insert notifications for affected groups.
-*/
-
-void QQmlListCompositor::setFlags(
- iterator from, int count, Group group, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< from << count << flags)
- if (!flags || !count)
- return;
-
- if (from != group) {
- // Skip to the next full range if the start one is not a member of the target group.
- from.incrementIndexes(from->count - from.offset);
- from.offset = 0;
- *from = from->next;
- } else if (from.offset > 0) {
- // If the start position is mid range split off the portion unaffected.
- *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
- from->index += from.offset;
- from->count -= from.offset;
- from.offset = 0;
- }
-
- for (; count > 0; *from = from->next) {
- if (from != from.group) {
- // Skip ranges that are not members of the target group.
- from.incrementIndexes(from->count);
- continue;
- }
- // Find the number of items affected in the current range.
- const int difference = qMin(count, from->count);
- count -= difference;
-
- // Determine the actual changes made to the range and increment counts accordingly.
- const uint insertFlags = ~from->flags & flags;
- const uint setFlags = (from->flags | flags) & ~AppendFlag;
- if (insertFlags && inserts)
- inserts->append(Insert(from, difference, insertFlags | (from->flags & CacheFlag)));
- m_end.incrementIndexes(difference, insertFlags);
- from.incrementIndexes(difference, setFlags);
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == setFlags) {
- // If the additional flags make the current range a continuation of the previous
- // then move the affected items over to the previous range.
- from->previous->count += difference;
- from->index += difference;
- from->count -= difference;
- if (from->count == 0) {
- // Delete the current range if it is now empty, preserving the append flag
- // in the previous range.
- if (from->append())
- from->previous->flags |= AppendFlag;
- *from = erase(*from)->previous;
- continue;
- } else {
- break;
- }
- } else if (!insertFlags) {
- // No new flags, so roll onto the next range.
- from.incrementIndexes(from->count - difference);
- continue;
- } else if (difference < from->count) {
- // Create a new range with the updated flags, and remove the affected items
- // from the current range.
- *from = insert(*from, from->list, from->index, difference, setFlags)->next;
- from->index += difference;
- from->count -= difference;
- } else {
- // The whole range is affected so simply update the flags.
- from->flags |= flags;
- continue;
- }
- from.incrementIndexes(from->count);
- }
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == (from->flags & ~AppendFlag)) {
- // If the following range is now a continuation, merge it with its previous range.
- from.offset = from->previous->count;
- from->previous->count += from->count;
- from->previous->flags = from->flags;
- *from = erase(*from)->previous;
- }
- m_cacheIt = from;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Clears the given flags \a flags on \a count items belonging to \a group starting at the position
- \a from.
-
- If supplied the \a removes list will be populated with remove notifications for affected groups.
-*/
-
-void QQmlListCompositor::clearFlags(
- Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
- clearFlags(find(fromGroup, from), count, group, flags, removes);
-}
-
-/*!
- Clears the given flags \a flags on \a count items belonging to \a group starting at the position
- identified by \a fromGroup and the index \a from.
-
- If supplied the \a removes list will be populated with remove notifications for affected groups.
-*/
-
-void QQmlListCompositor::clearFlags(
- iterator from, int count, Group group, uint flags, QVector<Remove> *removes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< from << count << flags)
- if (!flags || !count)
- return;
-
- const bool clearCache = flags & CacheFlag;
-
- if (from != group) {
- // Skip to the next full range if the start one is not a member of the target group.
- from.incrementIndexes(from->count - from.offset);
- from.offset = 0;
- *from = from->next;
- } else if (from.offset > 0) {
- // If the start position is mid range split off the portion unaffected.
- *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
- from->index += from.offset;
- from->count -= from.offset;
- from.offset = 0;
- }
-
- for (; count > 0; *from = from->next) {
- if (from != group) {
- // Skip ranges that are not members of the target group.
- from.incrementIndexes(from->count);
- continue;
- }
- // Find the number of items affected in the current range.
- const int difference = qMin(count, from->count);
- count -= difference;
-
-
- // Determine the actual changes made to the range and decrement counts accordingly.
- const uint removeFlags = from->flags & flags & ~(AppendFlag | PrependFlag);
- const uint clearedFlags = from->flags & ~(flags | AppendFlag | UnresolvedFlag);
- if (removeFlags && removes) {
- const int maskedFlags = clearCache
- ? (removeFlags & ~CacheFlag)
- : (removeFlags | (from->flags & CacheFlag));
- if (maskedFlags)
- removes->append(Remove(from, difference, maskedFlags));
- }
- m_end.decrementIndexes(difference, removeFlags);
- from.incrementIndexes(difference, clearedFlags);
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || clearedFlags == CacheFlag || from->previous->end() == from->index)
- && from->previous->flags == clearedFlags) {
- // If the removed flags make the current range a continuation of the previous
- // then move the affected items over to the previous range.
- from->previous->count += difference;
- from->index += difference;
- from->count -= difference;
- if (from->count == 0) {
- // Delete the current range if it is now empty, preserving the append flag
- if (from->append())
- from->previous->flags |= AppendFlag;
- *from = erase(*from)->previous;
- } else {
- from.incrementIndexes(from->count);
- }
- } else if (difference < from->count) {
- // Create a new range with the reduced flags, and remove the affected items from
- // the current range.
- if (clearedFlags)
- *from = insert(*from, from->list, from->index, difference, clearedFlags)->next;
- from->index += difference;
- from->count -= difference;
- from.incrementIndexes(from->count);
- } else if (clearedFlags) {
- // The whole range is affected so simply update the flags.
- from->flags &= ~flags;
- } else {
- // All flags have been removed from the range so remove it.
- *from = erase(*from)->previous;
- }
- }
-
- if (*from != &m_ranges && from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == (from->flags & ~AppendFlag)) {
- // If the following range is now a continuation, merge it with its previous range.
- from.offset = from->previous->count;
- from->previous->count += from->count;
- from->previous->flags = from->flags;
- *from = erase(*from)->previous;
- }
- m_cacheIt = from;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-bool QQmlListCompositor::verifyMoveTo(
- Group fromGroup, int from, Group toGroup, int to, int count, Group group) const
-{
- if (group != toGroup) {
- // determine how many items from the destination group intersect with the source group.
- iterator fromIt = find(fromGroup, from);
-
- int intersectingCount = 0;
-
- for (; count > 0; *fromIt = fromIt->next) {
- if (*fromIt == &m_ranges)
- return false;
- if (!fromIt->inGroup(group))
- continue;
- if (fromIt->inGroup(toGroup))
- intersectingCount += qMin(count, fromIt->count - fromIt.offset);
- count -= fromIt->count - fromIt.offset;
- fromIt.offset = 0;
- }
- count = intersectingCount;
- }
-
- return to >= 0 && to + count <= m_end.index[toGroup];
-}
-
-/*!
- \internal
-
- Moves \a count items belonging to \a moveGroup from the index \a from in \a fromGroup
- to the index \a to in \a toGroup.
-
- If \a removes and \a inserts are not null they will be populated with per group notifications
- of the items moved.
- */
-
-void QQmlListCompositor::move(
- Group fromGroup,
- int from,
- Group toGroup,
- int to,
- int count,
- Group moveGroup,
- QVector<Remove> *removes,
- QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << toGroup << to << count)
- Q_ASSERT(count > 0);
- Q_ASSERT(from >=0);
- Q_ASSERT(verifyMoveTo(fromGroup, from, toGroup, to, count, moveGroup));
-
- // Find the position of the first item to move.
- iterator fromIt = find(fromGroup, from);
-
- if (fromIt != moveGroup) {
- // If the range at the from index doesn't contain items from the move group; skip
- // to the next range.
- fromIt.incrementIndexes(fromIt->count - fromIt.offset);
- fromIt.offset = 0;
- *fromIt = fromIt->next;
- } else if (fromIt.offset > 0) {
- // If the range at the from index contains items from the move group and the index isn't
- // at the start of the range; split the range at the index and move the iterator to start
- // of the second range.
- *fromIt = insert(
- *fromIt, fromIt->list, fromIt->index, fromIt.offset, fromIt->flags & ~AppendFlag)->next;
- fromIt->index += fromIt.offset;
- fromIt->count -= fromIt.offset;
- fromIt.offset = 0;
- }
-
- // Remove count items belonging to the move group from the list.
- Range movedFlags;
- for (int moveId = m_moveId; count > 0;) {
- if (fromIt != moveGroup) {
- // Skip ranges not containing items from the move group.
- fromIt.incrementIndexes(fromIt->count);
- *fromIt = fromIt->next;
- continue;
- }
- int difference = qMin(count, fromIt->count);
-
- // Create a new static range containing the moved items from an existing range.
- new Range(
- &movedFlags,
- fromIt->list,
- fromIt->index,
- difference,
- fromIt->flags & ~(PrependFlag | AppendFlag));
- // Remove moved items from the count, the existing range, and a remove notification.
- if (removes)
- removes->append(Remove(fromIt, difference, fromIt->flags, ++moveId));
- count -= difference;
- fromIt->count -= difference;
-
- // If the existing range contains the prepend flag replace the removed items with
- // a placeholder range for new items inserted into the source model.
- int removeIndex = fromIt->index;
- if (fromIt->prepend()
- && fromIt->previous != &m_ranges
- && fromIt->previous->flags == PrependFlag
- && fromIt->previous->list == fromIt->list
- && fromIt->previous->end() == fromIt->index) {
- // Grow the previous range instead of creating a new one if possible.
- fromIt->previous->count += difference;
- } else if (fromIt->prepend()) {
- *fromIt = insert(*fromIt, fromIt->list, removeIndex, difference, PrependFlag)->next;
- }
- fromIt->index += difference;
-
- if (fromIt->count == 0) {
- // If the existing range has no items remaining; remove it from the list.
- if (fromIt->append())
- fromIt->previous->flags |= AppendFlag;
- *fromIt = erase(*fromIt);
-
- // If the ranges before and after the removed range can be joined, do so.
- if (*fromIt != m_ranges.next && fromIt->flags == PrependFlag
- && fromIt->previous != &m_ranges
- && fromIt->previous->flags == PrependFlag
- && fromIt->previous->list == fromIt->list
- && fromIt->previous->end() == fromIt->index) {
- fromIt.incrementIndexes(fromIt->count);
- fromIt->previous->count += fromIt->count;
- *fromIt = erase(*fromIt);
- }
- } else if (count > 0) {
- *fromIt = fromIt->next;
- }
- }
-
- // Try and join the range following the removed items to the range preceding it.
- if (*fromIt != m_ranges.next
- && *fromIt != &m_ranges
- && fromIt->previous->list == fromIt->list
- && (!fromIt->list || fromIt->previous->end() == fromIt->index)
- && fromIt->previous->flags == (fromIt->flags & ~AppendFlag)) {
- if (fromIt == fromIt.group)
- fromIt.offset = fromIt->previous->count;
- fromIt.offset = fromIt->previous->count;
- fromIt->previous->count += fromIt->count;
- fromIt->previous->flags = fromIt->flags;
- *fromIt = erase(*fromIt)->previous;
- }
-
- // Find the destination position of the move.
- insert_iterator toIt = fromIt;
- toIt.setGroup(toGroup);
-
- const int difference = to - toIt.index[toGroup];
- toIt += difference;
-
- // If the insert position is part way through a range; split it and move the iterator to the
- // start of the second range.
- if (toIt.offset > 0) {
- *toIt = insert(*toIt, toIt->list, toIt->index, toIt.offset, toIt->flags & ~AppendFlag)->next;
- toIt->index += toIt.offset;
- toIt->count -= toIt.offset;
- toIt.offset = 0;
- }
-
- // Insert the moved ranges before the insert iterator, growing the previous range if that
- // is an option.
- for (Range *range = movedFlags.previous; range != &movedFlags; range = range->previous) {
- if (*toIt != &m_ranges
- && range->list == toIt->list
- && (!range->list || range->end() == toIt->index)
- && range->flags == (toIt->flags & ~AppendFlag)) {
- toIt->index -= range->count;
- toIt->count += range->count;
- } else {
- *toIt = insert(*toIt, range->list, range->index, range->count, range->flags);
- }
- }
-
- // Try and join the range after the inserted ranges to the last range inserted.
- if (*toIt != m_ranges.next
- && toIt->previous->list == toIt->list
- && (!toIt->list || (toIt->previous->end() == toIt->index && toIt->previous->flags == (toIt->flags & ~AppendFlag)))) {
- toIt.offset = toIt->previous->count;
- toIt->previous->count += toIt->count;
- toIt->previous->flags = toIt->flags;
- *toIt = erase(*toIt)->previous;
- }
- // Create insert notification for the ranges moved.
- Insert insert(toIt, 0, 0, 0);
- for (Range *next, *range = movedFlags.next; range != &movedFlags; range = next) {
- insert.count = range->count;
- insert.flags = range->flags;
- if (inserts) {
- insert.moveId = ++m_moveId;
- inserts->append(insert);
- }
- for (int i = 0; i < m_groupCount; ++i) {
- if (insert.inGroup(i))
- insert.index[i] += range->count;
- }
-
- next = range->next;
- delete range;
- }
-
- m_cacheIt = toIt;
-
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Clears the contents of a compositor.
-*/
-
-void QQmlListCompositor::clear()
-{
- QT_QML_TRACE_LISTCOMPOSITOR("")
- for (Range *range = m_ranges.next; range != &m_ranges; range = erase(range)) {}
- m_end = iterator(m_ranges.next, 0, Default, m_groupCount);
- m_cacheIt = m_end;
-}
-
-void QQmlListCompositor::listItemsInserted(
- QVector<Insert> *translatedInsertions,
- void *list,
- const QVector<QQmlChangeSet::Change> &insertions,
- const QVector<MovedFlags> *movedFlags)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << insertions)
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- // Skip ranges that don't reference list.
- it.incrementIndexes(it->count);
- continue;
- } else if (it->flags & MovedFlag) {
- // Skip ranges that were already moved in listItemsRemoved.
- it->flags &= ~MovedFlag;
- it.incrementIndexes(it->count);
- continue;
- }
- for (const QQmlChangeSet::Change &insertion : insertions) {
- int offset = insertion.index - it->index;
- if ((offset > 0 && offset < it->count)
- || (offset == 0 && it->prepend())
- || (offset == it->count && it->append())) {
- // The insert index is within the current range.
- if (it->prepend()) {
- // The range has the prepend flag set so we insert new items into the range.
- uint flags = m_defaultFlags;
- if (insertion.isMove()) {
- // If the insert was part of a move replace the default flags with
- // the flags from the source range.
- for (QVector<MovedFlags>::const_iterator move = movedFlags->begin();
- move != movedFlags->end();
- ++move) {
- if (move->moveId == insertion.moveId) {
- flags = move->flags;
- break;
- }
- }
- }
- if (flags & ~(AppendFlag | PrependFlag)) {
- // If any items are added to groups append an insert notification.
- Insert translatedInsert(it, insertion.count, flags, insertion.moveId);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedInsert.index[i] += offset;
- }
- translatedInsertions->append(translatedInsert);
- }
- if ((it->flags & ~AppendFlag) == flags) {
- // Accumulate items on the current range it its flags are the same as
- // the insert flags.
- it->count += insertion.count;
- } else if (offset == 0
- && it->previous != &m_ranges
- && it->previous->list == list
- && it->previous->end() == insertion.index
- && it->previous->flags == flags) {
- // Attempt to append to the previous range if the insert position is at
- // the start of the current range.
- it->previous->count += insertion.count;
- it->index += insertion.count;
- it.incrementIndexes(insertion.count);
- } else {
- if (offset > 0) {
- // Divide the current range at the insert position.
- it.incrementIndexes(offset);
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- }
- // Insert a new range, and increment the start index of the current range.
- *it = insert(*it, it->list, insertion.index, insertion.count, flags)->next;
- it.incrementIndexes(insertion.count, flags);
- it->index += offset + insertion.count;
- it->count -= offset;
- }
- m_end.incrementIndexes(insertion.count, flags);
- } else {
- // The range doesn't have the prepend flag set so split the range into parts;
- // one before the insert position and one after the last inserted item.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags)->next;
- it->index += offset;
- it->count -= offset;
- }
- it->index += insertion.count;
- }
- } else if (offset <= 0) {
- // The insert position was before the current range so increment the start index.
- it->index += insertion.count;
- }
- }
- it.incrementIndexes(it->count);
- }
- m_cacheIt = m_end;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Updates the contents of a compositor when \a count items are inserted into a \a list at
- \a index.
-
- This corrects the indexes of each range for that list in the compositor, splitting the range
- in two if the insert index is in the middle of that range. If a range at the insert position
- has the Prepend flag set then a new range will be inserted at that position with the groups
- specified in defaultGroups(). If the insert index corresponds to the end of a range with
- the Append flag set a new range will be inserted before the end of the append range.
-
- The \a translatedInsertions list is populated with insert notifications for affected
- groups.
-*/
-
-void QQmlListCompositor::listItemsInserted(
- void *list, int index, int count, QVector<Insert> *translatedInsertions)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count > 0);
-
- QVector<QQmlChangeSet::Change> insertions;
- insertions.append(QQmlChangeSet::Change(index, count));
-
- listItemsInserted(translatedInsertions, list, insertions);
-}
-
-void QQmlListCompositor::listItemsRemoved(
- QVector<Remove> *translatedRemovals,
- void *list,
- QVector<QQmlChangeSet::Change> *removals,
- QVector<QQmlChangeSet::Change> *insertions,
- QVector<MovedFlags> *movedFlags)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << *removals)
-
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- // Skip ranges that don't reference list.
- it.incrementIndexes(it->count);
- continue;
- }
- bool removed = false;
- for (QVector<QQmlChangeSet::Change>::iterator removal = removals->begin();
- !removed && removal != removals->end();
- ++removal) {
- int relativeIndex = removal->index - it->index;
- int itemsRemoved = removal->count;
- if (relativeIndex + removal->count > 0 && relativeIndex < it->count) {
- // If the current range intersects the remove; remove the intersecting items.
- const int offset = qMax(0, relativeIndex);
- int removeCount = qMin(it->count, relativeIndex + removal->count) - offset;
- it->count -= removeCount;
- int removeFlags = it->flags & m_removeFlags;
- Remove translatedRemoval(it, removeCount, it->flags);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedRemoval.index[i] += offset;
- }
- if (removal->isMove()) {
- // If the removal was part of a move find the corresponding insert.
- QVector<QQmlChangeSet::Change>::iterator insertion = insertions->begin();
- for (; insertion != insertions->end() && insertion->moveId != removal->moveId;
- ++insertion) {}
- Q_ASSERT(insertion != insertions->end());
- Q_ASSERT(insertion->count == removal->count);
-
- if (relativeIndex < 0) {
- // If the remove started before the current range, split it and the
- // corresponding insert so we're only working with intersecting part.
- int splitMoveId = ++m_moveId;
- removal = removals->insert(removal, QQmlChangeSet::Change(
- removal->index, -relativeIndex, splitMoveId));
- ++removal;
- removal->count -= -relativeIndex;
- insertion = insertions->insert(insertion, QQmlChangeSet::Change(
- insertion->index, -relativeIndex, splitMoveId));
- ++insertion;
- insertion->index += -relativeIndex;
- insertion->count -= -relativeIndex;
- }
-
- if (it->prepend()) {
- // If the current range has the prepend flag preserve its flags to transfer
- // to its new location.
- removeFlags |= it->flags & CacheFlag;
- translatedRemoval.moveId = ++m_moveId;
- movedFlags->append(MovedFlags(m_moveId, it->flags & ~AppendFlag));
-
- if (removeCount < removal->count) {
- // If the remove doesn't encompass all of the current range,
- // split it and the corresponding insert.
- removal = removals->insert(removal, QQmlChangeSet::Change(
- removal->index, removeCount, translatedRemoval.moveId));
- ++removal;
- insertion = insertions->insert(insertion, QQmlChangeSet::Change(
- insertion->index, removeCount, translatedRemoval.moveId));
- ++insertion;
-
- removal->count -= removeCount;
- insertion->index += removeCount;
- insertion->count -= removeCount;
- } else {
- // If there's no need to split the move simply replace its moveId
- // with that of the translated move.
- removal->moveId = translatedRemoval.moveId;
- insertion->moveId = translatedRemoval.moveId;
- }
- } else {
- // If the current range doesn't have prepend flags then insert a new range
- // with list indexes from the corresponding insert location. The MoveFlag
- // is to notify listItemsInserted that it can skip evaluation of that range.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- it->index += offset;
- it->count -= offset;
- it.incrementIndexes(offset);
- }
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->end() == insertion->index
- && it->previous->flags == (it->flags | MovedFlag)) {
- it->previous->count += removeCount;
- } else {
- *it = insert(*it, it->list, insertion->index, removeCount, it->flags | MovedFlag)->next;
- }
- // Clear the changed flags as the item hasn't been removed.
- translatedRemoval.flags = 0;
- removeFlags = 0;
- }
- } else if (it->inCache()) {
- // If not moving and the current range has the cache flag, insert a new range
- // with just the cache flag set to retain caching information for the removed
- // range.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- it->index += offset;
- it->count -= offset;
- it.incrementIndexes(offset);
- }
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->previous->flags == CacheFlag) {
- it->previous->count += removeCount;
- } else {
- *it = insert(*it, it->list, -1, removeCount, CacheFlag)->next;
- }
- it.index[Cache] += removeCount;
- }
- if (removeFlags & GroupMask)
- translatedRemovals->append(translatedRemoval);
- m_end.decrementIndexes(removeCount, removeFlags);
- if (it->count == 0 && !it->append()) {
- // Erase empty non-append ranges.
- *it = erase(*it)->previous;
- removed = true;
- } else if (relativeIndex <= 0) {
- // If the remove started before the current range move the start index of
- // the range to the remove index.
- it->index = removal->index;
- }
- } else if (relativeIndex < 0) {
- // If the remove was before the current range decrement the start index by the
- // number of items removed.
- it->index -= itemsRemoved;
-
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->previous->end() == it->index
- && it->previous->flags == (it->flags & ~AppendFlag)) {
- // Compress ranges made continuous by the removal of separating ranges.
- it.decrementIndexes(it->previous->count);
- it->previous->count += it->count;
- it->previous->flags = it->flags;
- *it = erase(*it)->previous;
- }
- }
- }
- if (it->flags == CacheFlag && it->next->flags == CacheFlag && it->next->list == it->list) {
- // Compress consecutive cache only ranges.
- it.index[Cache] += it->next->count;
- it->count += it->next->count;
- erase(it->next);
- } else if (!removed) {
- it.incrementIndexes(it->count);
- }
- }
- m_cacheIt = m_end;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-
-/*!
- Updates the contents of a compositor when \a count items are removed from a \a list at
- \a index.
-
- Ranges that intersect the specified range are removed from the compositor and the indexes of
- ranges after index + count are updated.
-
- The \a translatedRemovals list is populated with remove notifications for the affected
- groups.
-*/
-
-
-void QQmlListCompositor::listItemsRemoved(
- void *list, int index, int count, QVector<Remove> *translatedRemovals)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count >= 0);
-
- QVector<QQmlChangeSet::Change> removals;
- removals.append(QQmlChangeSet::Change(index, count));
- listItemsRemoved(translatedRemovals, list, &removals, nullptr, nullptr);
-}
-
-/*!
- Updates the contents of a compositor when \a count items are removed from a \a list at
- \a index.
-
- Ranges that intersect the specified range are removed from the compositor and the indexes of
- ranges after index + count are updated.
-
- The \a translatedRemovals and translatedInserts lists are populated with move
- notifications for the affected groups.
-*/
-
-void QQmlListCompositor::listItemsMoved(
- void *list,
- int from,
- int to,
- int count,
- QVector<Remove> *translatedRemovals,
- QVector<Insert> *translatedInsertions)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << from << to << count)
- Q_ASSERT(count >= 0);
-
- QVector<QQmlChangeSet::Change> removals;
- QVector<QQmlChangeSet::Change> insertions;
- QVector<MovedFlags> movedFlags;
- removals.append(QQmlChangeSet::Change(from, count, 0));
- insertions.append(QQmlChangeSet::Change(to, count, 0));
-
- listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags);
- listItemsInserted(translatedInsertions, list, insertions, &movedFlags);
-}
-
-void QQmlListCompositor::listItemsChanged(
- QVector<Change> *translatedChanges,
- void *list,
- const QVector<QQmlChangeSet::Change> &changes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << changes)
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- it.incrementIndexes(it->count);
- continue;
- } else if (!it->inGroup()) {
- continue;
- }
- for (const QQmlChangeSet::Change &change : changes) {
- const int offset = change.index - it->index;
- if (offset + change.count > 0 && offset < it->count) {
- const int changeOffset = qMax(0, offset);
- const int changeCount = qMin(it->count, offset + change.count) - changeOffset;
-
- Change translatedChange(it, changeCount, it->flags);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedChange.index[i] += changeOffset;
- }
- translatedChanges->append(translatedChange);
- }
- }
- it.incrementIndexes(it->count);
- }
-}
-
-
-/*!
- Translates the positions of \a count changed items at \a index in a \a list.
-
- The \a translatedChanges list is populated with change notifications for the
- affected groups.
-*/
-
-void QQmlListCompositor::listItemsChanged(
- void *list, int index, int count, QVector<Change> *translatedChanges)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count >= 0);
- QVector<QQmlChangeSet::Change> changes;
- changes.append(QQmlChangeSet::Change(index, count));
- listItemsChanged(translatedChanges, list, changes);
-}
-
-void QQmlListCompositor::transition(
- Group from,
- Group to,
- QVector<QQmlChangeSet::Change> *removes,
- QVector<QQmlChangeSet::Change> *inserts)
-{
- int removeCount = 0;
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it == from && it != to) {
- removes->append(QQmlChangeSet::Change(it.index[from]- removeCount, it->count));
- removeCount += it->count;
- } else if (it != from && it == to) {
- inserts->append(QQmlChangeSet::Change(it.index[to], it->count));
- }
- it.incrementIndexes(it->count);
- }
-}
-
-/*!
- \internal
- Writes the name of \a group to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group)
-{
- switch (group) {
- case QQmlListCompositor::Cache: return debug << "Cache";
- case QQmlListCompositor::Default: return debug << "Default";
- default: return (debug.nospace() << "Group" << int(group)).space();
- }
-
-}
-
-/*!
- \internal
- Writes the contents of \a range to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range)
-{
- (debug.nospace()
- << "Range("
- << range.list) << ' '
- << range.index << ' '
- << range.count << ' '
- << (range.isUnresolved() ? 'U' : '0')
- << (range.append() ? 'A' : '0')
- << (range.prepend() ? 'P' : '0');
- for (int i = QQmlListCompositor::MaximumGroupCount - 1; i >= 2; --i)
- debug << (range.inGroup(i) ? '1' : '0');
- return (debug
- << (range.inGroup(QQmlListCompositor::Default) ? 'D' : '0')
- << (range.inGroup(QQmlListCompositor::Cache) ? 'C' : '0'));
-}
-
-static void qt_print_indexes(QDebug &debug, int count, const int *indexes)
-{
- for (int i = count - 1; i >= 0; --i)
- debug << indexes[i];
-}
-
-/*!
- \internal
- Writes the contents of \a it to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it)
-{
- (debug.nospace() << "iterator(" << it.group).space() << "offset:" << it.offset;
- qt_print_indexes(debug, it.groupCount, it.index);
- return ((debug << **it).nospace() << ')').space();
-}
-
-static QDebug qt_print_change(QDebug debug, const char *name, const QQmlListCompositor::Change &change)
-{
- debug.nospace() << name << '(' << change.moveId << ' ' << change.count << ' ';
- for (int i = QQmlListCompositor::MaximumGroupCount - 1; i >= 2; --i)
- debug << (change.inGroup(i) ? '1' : '0');
- debug << (change.inGroup(QQmlListCompositor::Default) ? 'D' : '0')
- << (change.inGroup(QQmlListCompositor::Cache) ? 'C' : '0');
- int i = QQmlListCompositor::MaximumGroupCount - 1;
- for (; i >= 0 && !change.inGroup(i); --i) {}
- for (; i >= 0; --i)
- debug << ' ' << change.index[i];
- return (debug << ')').maybeSpace();
-}
-
-/*!
- \internal
- Writes the contents of \a change to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change)
-{
- return qt_print_change(debug, "Change", change);
-}
-
-/*!
- \internal
- Writes the contents of \a remove to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove)
-{
- return qt_print_change(debug, "Remove", remove);
-}
-
-/*!
- \internal
- Writes the contents of \a insert to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert)
-{
- return qt_print_change(debug, "Insert", insert);
-}
-
-/*!
- \internal
- Writes the contents of \a list to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor &list)
-{
- int indexes[QQmlListCompositor::MaximumGroupCount];
- for (int i = 0; i < QQmlListCompositor::MaximumGroupCount; ++i)
- indexes[i] = 0;
- debug.nospace() << "QQmlListCompositor(";
- qt_print_indexes(debug, list.m_groupCount, list.m_end.index);
- for (QQmlListCompositor::Range *range = list.m_ranges.next; range != &list.m_ranges; range = range->next) {
- (debug << '\n').space();
- qt_print_indexes(debug, list.m_groupCount, indexes);
- debug << ' ' << *range;
-
- for (int i = 0; i < list.m_groupCount; ++i) {
- if (range->inGroup(i))
- indexes[i] += range->count;
- }
- }
- return (debug << ')').maybeSpace();
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qml/util/qqmllistcompositor_p.h
deleted file mode 100644
index 172040559c..0000000000
--- a/src/qml/util/qqmllistcompositor_p.h
+++ /dev/null
@@ -1,372 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTCOMPOSITOR_P_H
-#define QQMLLISTCOMPOSITOR_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qvector.h>
-
-#include <private/qqmlchangeset_p.h>
-
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT QQmlListCompositor
-{
-public:
- enum { MinimumGroupCount = 3, MaximumGroupCount = 11 };
-
- enum Group
- {
- Cache = 0,
- Default = 1,
- Persisted = 2
- };
-
- enum Flag
- {
- CacheFlag = 1 << Cache,
- DefaultFlag = 1 << Default,
- PersistedFlag = 1 << Persisted,
- PrependFlag = 0x10000000,
- AppendFlag = 0x20000000,
- UnresolvedFlag = 0x40000000,
- MovedFlag = 0x80000000,
- GroupMask = ~(PrependFlag | AppendFlag | UnresolvedFlag | MovedFlag | CacheFlag)
- };
-
- class Range
- {
- public:
- Range() : next(this), previous(this) {}
- Range(Range *next, void *list, int index, int count, uint flags)
- : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) {
- next->previous = this; previous->next = this; }
-
- Range *next;
- Range *previous;
- void *list = nullptr;
- int index = 0;
- int count = 0;
- uint flags = 0;
-
- inline int start() const { return index; }
- inline int end() const { return index + count; }
-
- inline int groups() const { return flags & GroupMask; }
-
- inline bool inGroup() const { return flags & GroupMask; }
- inline bool inCache() const { return flags & CacheFlag; }
- inline bool inGroup(int group) const { return flags & (1 << group); }
- inline bool isUnresolved() const { return flags & UnresolvedFlag; }
-
- inline bool prepend() const { return flags & PrependFlag; }
- inline bool append() const { return flags & AppendFlag; }
- };
-
- class Q_AUTOTEST_EXPORT iterator
- {
- public:
- inline iterator();
- inline iterator(const iterator &it);
- inline iterator(Range *range, int offset, Group group, int groupCount);
- inline ~iterator() {}
-
- bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; }
- bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; }
-
- bool operator ==(Group group) const { return range->flags & (1 << group); }
- bool operator !=(Group group) const { return !(range->flags & (1 << group)); }
-
- Range *&operator *() { return range; }
- Range * const &operator *() const { return range; }
- Range *operator ->() { return range; }
- const Range *operator ->() const { return range; }
-
- iterator &operator +=(int difference);
-
- template<typename T> T *list() const { return static_cast<T *>(range->list); }
- int modelIndex() const { return range->index + offset; }
-
- void incrementIndexes(int difference) { incrementIndexes(difference, range->flags); }
- void decrementIndexes(int difference) { decrementIndexes(difference, range->flags); }
-
- inline void incrementIndexes(int difference, uint flags);
- inline void decrementIndexes(int difference, uint flags);
-
- void setGroup(Group g) { group = g; groupFlag = 1 << g; }
-
- Range *range = nullptr;
- int offset = 0;
- Group group = Default;
- int groupFlag;
- int groupCount = 0;
- union {
- struct {
- int cacheIndex;
- };
- int index[MaximumGroupCount];
- };
- };
-
- class Q_AUTOTEST_EXPORT insert_iterator : public iterator
- {
- public:
- inline insert_iterator() {}
- inline insert_iterator(const iterator &it) : iterator(it) {}
- inline insert_iterator(Range *, int, Group, int);
- inline ~insert_iterator() {}
-
- insert_iterator &operator +=(int difference);
- };
-
- struct Change
- {
- inline Change() {}
- inline Change(const iterator &it, int count, uint flags, int moveId = -1);
- int count;
- uint flags;
- int moveId;
- union {
- struct {
- int cacheIndex;
- };
- int index[MaximumGroupCount];
- };
-
- inline bool isMove() const { return moveId >= 0; }
- inline bool inCache() const { return flags & CacheFlag; }
- inline bool inGroup() const { return flags & GroupMask; }
- inline bool inGroup(int group) const { return flags & (CacheFlag << group); }
-
- inline int groups() const { return flags & GroupMask; }
- };
-
- struct Insert : public Change
- {
- Insert() {}
- Insert(const iterator &it, int count, uint flags, int moveId = -1)
- : Change(it, count, flags, moveId) {}
- };
-
- struct Remove : public Change
- {
- Remove() {}
- Remove(const iterator &it, int count, uint flags, int moveId = -1)
- : Change(it, count, flags, moveId) {}
- };
-
- QQmlListCompositor();
- ~QQmlListCompositor();
-
- int defaultGroups() const { return m_defaultFlags & ~PrependFlag; }
- void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
- void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
- void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
- void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
- void setGroupCount(int count);
-
- int count(Group group) const;
- iterator find(Group group, int index);
- iterator find(Group group, int index) const;
- insert_iterator findInsertPosition(Group group, int index);
-
- const iterator &end() { return m_end; }
-
- void append(void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
- void insert(Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
- iterator insert(iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
-
- void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts = nullptr);
- void setFlags(iterator from, int count, Group group, uint flags, QVector<Insert> *inserts = nullptr);
- void setFlags(Group fromGroup, int from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
- setFlags(fromGroup, from, count, fromGroup, flags, inserts); }
- void setFlags(const iterator from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
- setFlags(from, count, from.group, flags, inserts); }
-
- void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
- void clearFlags(iterator from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
- void clearFlags(Group fromGroup, int from, int count, uint flags, QVector<Remove> *removals = nullptr) {
- clearFlags(fromGroup, from, count, fromGroup, flags, removals); }
- void clearFlags(const iterator &from, int count, uint flags, QVector<Remove> *removals = nullptr) {
- clearFlags(from, count, from.group, flags, removals); }
-
- bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const;
-
- void move(
- Group fromGroup,
- int from,
- Group toGroup,
- int to,
- int count,
- Group group,
- QVector<Remove> *removals = nullptr,
- QVector<Insert> *inserts = nullptr);
- void clear();
-
- void listItemsInserted(void *list, int index, int count, QVector<Insert> *inserts);
- void listItemsRemoved(void *list, int index, int count, QVector<Remove> *removals);
- void listItemsMoved(void *list, int from, int to, int count, QVector<Remove> *removals, QVector<Insert> *inserts);
- void listItemsChanged(void *list, int index, int count, QVector<Change> *changes);
-
- void transition(
- Group from,
- Group to,
- QVector<QQmlChangeSet::Change> *removes,
- QVector<QQmlChangeSet::Change> *inserts);
-
-private:
- Range m_ranges;
- iterator m_end;
- iterator m_cacheIt;
- int m_groupCount;
- int m_defaultFlags;
- int m_removeFlags;
- int m_moveId;
-
- inline Range *insert(Range *before, void *list, int index, int count, uint flags);
- inline Range *erase(Range *range);
-
- struct MovedFlags
- {
- MovedFlags() {}
- MovedFlags(int moveId, uint flags) : moveId(moveId), flags(flags) {}
-
- int moveId;
- uint flags;
- };
-
- void listItemsRemoved(
- QVector<Remove> *translatedRemovals,
- void *list,
- QVector<QQmlChangeSet::Change> *removals,
- QVector<QQmlChangeSet::Change> *insertions = nullptr,
- QVector<MovedFlags> *movedFlags = nullptr);
- void listItemsInserted(
- QVector<Insert> *translatedInsertions,
- void *list,
- const QVector<QQmlChangeSet::Change> &insertions,
- const QVector<MovedFlags> *movedFlags = nullptr);
- void listItemsChanged(
- QVector<Change> *translatedChanges,
- void *list,
- const QVector<QQmlChangeSet::Change> &changes);
-
- friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
-};
-
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Change, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Remove, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
-
-inline QQmlListCompositor::iterator::iterator() {}
-inline QQmlListCompositor::iterator::iterator(const iterator &it)
- : range(it.range)
- , offset(it.offset)
- , group(it.group)
- , groupFlag(it.groupFlag)
- , groupCount(it.groupCount)
-{
- for (int i = 0; i < groupCount; ++i)
- index[i] = it.index[i];
-}
-
-inline QQmlListCompositor::iterator::iterator(
- Range *range, int offset, Group group, int groupCount)
- : range(range)
- , offset(offset)
- , group(group)
- , groupFlag(1 << group)
- , groupCount(groupCount)
-{
- for (int i = 0; i < groupCount; ++i)
- index[i] = 0;
-}
-
-inline void QQmlListCompositor::iterator::incrementIndexes(int difference, uint flags)
-{
- for (int i = 0; i < groupCount; ++i) {
- if (flags & (1 << i))
- index[i] += difference;
- }
-}
-
-inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint flags)
-{
- for (int i = 0; i < groupCount; ++i) {
- if (flags & (1 << i))
- index[i] -= difference;
- }
-}
-
-inline QQmlListCompositor::insert_iterator::insert_iterator(
- Range *range, int offset, Group group, int groupCount)
- : iterator(range, offset, group, groupCount) {}
-
-inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId)
- : count(count), flags(flags), moveId(moveId)
-{
- for (int i = 0; i < MaximumGroupCount; ++i)
- index[i] = it.index[i];
-}
-
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
index bebb271f1b..3b121ba3cb 100644
--- a/src/qml/util/util.pri
+++ b/src/qml/util/util.pri
@@ -1,19 +1,5 @@
SOURCES += \
- $$PWD/qqmlchangeset.cpp \
- $$PWD/qqmllistaccessor.cpp \
- $$PWD/qqmllistcompositor.cpp \
$$PWD/qqmlpropertymap.cpp
HEADERS += \
- $$PWD/qqmlchangeset_p.h \
- $$PWD/qqmllistaccessor_p.h \
- $$PWD/qqmllistcompositor_p.h \
$$PWD/qqmlpropertymap.h
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmladaptormodel.cpp
-
- HEADERS += \
- $$PWD/qqmladaptormodel_p.h
-}