summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 17:05:21 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 17:05:21 +0100
commit13e88fe2b9b1680cb161a249289c3ba998f08c0c (patch)
tree496a9d88c69b441e8c88aa0416b327faca3a1532 /src
parenta2dad3ddee9c4bf274a7c6469342e4104605ceeb (diff)
parent470ba767663e4ad9d3183fb56ee89361354dfefb (diff)
downloadqtdeclarative-13e88fe2b9b1680cb161a249289c3ba998f08c0c.tar.gz
Merge remote-tracking branch 'origin/stable' into dev
Conflicts: src/quick/items/qquickitem.cpp src/quick/items/qquicktext.cpp tests/auto/quick/qquicklistview/tst_qquicklistview.cpp Change-Id: I0bc5786098193c2c40b6fd8905de75d90f6ed0cf
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h10
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86Common.h20
-rw-r--r--src/imports/dialogs-private/qmldir1
-rw-r--r--src/imports/localstorage/plugin.cpp4
-rw-r--r--src/particles/qquickv4particledata.cpp2
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp47
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h24
-rw-r--r--src/qml/compiler/qv4codegen.cpp2
-rw-r--r--src/qml/compiler/qv4compiler.cpp91
-rw-r--r--src/qml/compiler/qv4compiler_p.h7
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp113
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp25
-rw-r--r--src/qml/compiler/qv4jsir.cpp20
-rw-r--r--src/qml/compiler/qv4jsir_p.h59
-rw-r--r--src/qml/compiler/qv4regalloc.cpp11
-rw-r--r--src/qml/compiler/qv4ssa.cpp998
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h6
-rw-r--r--src/qml/debugger/qv4debugservice.cpp8
-rw-r--r--src/qml/doc/qtqml.qdocconf4
-rw-r--r--src/qml/doc/snippets/package/Delegate.qml78
-rw-r--r--src/qml/doc/snippets/package/view.qml93
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc45
-rw-r--r--src/qml/jsapi/qjsengine.cpp51
-rw-r--r--src/qml/jsapi/qjsvalue.cpp89
-rw-r--r--src/qml/jsapi/qjsvalue_p.h7
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp6
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp148
-rw-r--r--src/qml/jsruntime/qv4context_p.h102
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h3
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp27
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp101
-rw-r--r--src/qml/jsruntime/qv4engine_p.h47
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4function.cpp35
-rw-r--r--src/qml/jsruntime/qv4function_p.h10
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp182
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h22
-rw-r--r--src/qml/jsruntime/qv4global_p.h2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp12
-rw-r--r--src/qml/jsruntime/qv4include.cpp6
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp60
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h14
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp6
-rw-r--r--src/qml/jsruntime/qv4managed.cpp36
-rw-r--r--src/qml/jsruntime/qv4managed_p.h42
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4mm.cpp10
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4object.cpp29
-rw-r--r--src/qml/jsruntime/qv4object_p.h14
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp6
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp24
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp3
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp32
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h6
-rw-r--r--src/qml/jsruntime/qv4script.cpp14
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp2
-rw-r--r--src/qml/jsruntime/qv4string.cpp27
-rw-r--r--src/qml/jsruntime/qv4string_p.h4
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4value.cpp6
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp2
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp14
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqml.h4
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp3
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.h (renamed from src/qml/qml/qqmlabstracturlinterceptor_p.h)4
-rw-r--r--src/qml/qml/qqmlbinding.cpp10
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp4
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp22
-rw-r--r--src/qml/qml/qqmlcompiler.cpp68
-rw-r--r--src/qml/qml/qqmlcompiler_p.h18
-rw-r--r--src/qml/qml/qqmlcomponent.cpp4
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp22
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp3
-rw-r--r--src/qml/qml/qqmlengine.cpp36
-rw-r--r--src/qml/qml/qqmlfileselector.cpp2
-rw-r--r--src/qml/qml/qqmlfileselector_p.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp3
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp6
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp6
-rw-r--r--src/qml/qml/qqmllocale.cpp4
-rw-r--r--src/qml/qml/qqmlmemoryprofiler.cpp3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp9
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp16
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp28
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp10
-rw-r--r--src/qml/qml/v8/qv8engine.cpp8
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp14
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qquickpackage.cpp6
-rw-r--r--src/qml/types/qquickworkerscript.cpp6
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp64
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h8
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp60
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h6
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp34
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp193
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h70
-rw-r--r--src/quick/items/items.pri1
-rw-r--r--src/quick/items/qquickflickable.cpp126
-rw-r--r--src/quick/items/qquickflickablebehavior_p.h105
-rw-r--r--src/quick/items/qquickitem.cpp15
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemview_p.h15
-rw-r--r--src/quick/items/qquicklistview.cpp68
-rw-r--r--src/quick/items/qquickloader.cpp5
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickpathview.cpp17
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp1
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp15
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquicktext.cpp98
-rw-r--r--src/quick/items/qquicktextinput.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp44
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--src/quick/items/qquickwindowmodule.cpp80
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp14
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h4
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp6
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp76
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h2
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp1
-rw-r--r--src/quick/util/qquickapplication.cpp2
-rw-r--r--src/quick/util/qquickpixmapcache.cpp22
149 files changed, 2901 insertions, 1633 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 61c13acd35..9a8dc1f358 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -177,6 +177,11 @@ public:
}
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.add(dest, op1, op2);
+ }
+
void add32(TrustedImm32 imm, Address address)
{
load32(address, dataTempRegister);
@@ -310,6 +315,11 @@ public:
m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.smull(dest, dataTempRegister, op1, op2);
+ }
+
void neg32(RegisterID srcDest)
{
m_assembler.neg(srcDest, srcDest);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
index 520cf915fa..94771be6a7 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
@@ -146,6 +146,16 @@ public:
m_assembler.andl_rr(src, dest);
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest) {
+ add32(op1, dest);
+ } else {
+ move(op1, dest);
+ add32(op2, dest);
+ }
+ }
+
void and32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.andl_ir(imm.m_value, dest);
@@ -226,6 +236,16 @@ public:
m_assembler.imull_rr(src, dest);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest) {
+ mul32(op1, dest);
+ } else {
+ move(op1, dest);
+ mul32(op2, dest);
+ }
+ }
+
void mul32(Address src, RegisterID dest)
{
m_assembler.imull_mr(src.offset, src.base, dest);
diff --git a/src/imports/dialogs-private/qmldir b/src/imports/dialogs-private/qmldir
index e184715519..c371f8bb8c 100644
--- a/src/imports/dialogs-private/qmldir
+++ b/src/imports/dialogs-private/qmldir
@@ -1,3 +1,4 @@
module QtQuick.Dialogs.Private
plugin dialogsprivateplugin
typeinfo plugins.qmltypes
+classname QtQuick2DialogsPrivatePlugin
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 145487cf3e..48693dbbf3 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -108,7 +108,7 @@ public:
QQmlSqlDatabaseWrapper(QV8Engine *e)
: Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~QQmlSqlDatabaseWrapper() {
@@ -659,7 +659,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
{
#ifndef QT_NO_SETTINGS
QV8Engine *engine = args->engine();
- QV4::ExecutionContext *ctx = args->v4engine()->current;
+ QV4::ExecutionContext *ctx = args->v4engine()->currentContext();
QV4::Scope scope(ctx);
if (engine->engine()->offlineStoragePath().isEmpty())
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index 6f9cd829bb..d0e9a392d4 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -277,7 +277,7 @@ struct QV4ParticleData : public QV4::Object
QV4ParticleData(QV4::ExecutionEngine *engine, QQuickParticleData *datum)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
this->datum = datum;
}
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 15004801f5..8809221abe 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -281,7 +281,7 @@ bool QQmlCodeGenerator::sanityCheckFunctionNames()
{
QSet<QString> functionNames;
for (Function *f = _object->functions->first; f; f = f->next) {
- AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index));
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index).node);
Q_ASSERT(function);
QString name = function->name.toString();
if (functionNames.contains(name))
@@ -1204,13 +1204,13 @@ int QmlUnitGenerator::getStringId(const QString &str) const
return jsUnitGenerator->getStringId(str);
}
-JSCodeGen::JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
+JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
: QQmlJS::Codegen(/*strict mode*/false)
- , engine(enginePrivate)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
, imports(imports)
+ , _disableAcceleratedLookups(false)
, _contextObject(0)
, _scopeObject(0)
, _contextObjectTemp(-1)
@@ -1235,23 +1235,23 @@ void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject)
_scopeObject = scopeObject;
}
-QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames)
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions)
{
QVector<int> runtimeFunctionIndices(functions.size());
ScanFunctions scan(this, sourceCode, GlobalCode);
scan.enterEnvironment(0, QmlBinding);
scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
- foreach (AST::Node *node, functions) {
- Q_ASSERT(node != qmlRoot);
- AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
+ foreach (const CompiledFunctionOrExpression &f, functions) {
+ Q_ASSERT(f.node != qmlRoot);
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(f.node);
if (function)
scan.enterQmlFunction(function);
else
- scan.enterEnvironment(node, QmlBinding);
+ scan.enterEnvironment(f.node, QmlBinding);
- scan(function ? function->body : node);
+ scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
scan.leaveEnvironment();
@@ -1261,7 +1261,8 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
_function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
- AST::Node *node = functions.at(i);
+ const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
+ AST::Node *node = qmlFunction.node;
Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
@@ -1269,8 +1270,10 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
QString name;
if (function)
name = function->name.toString();
+ else if (!qmlFunction.name.isEmpty())
+ name = qmlFunction.name;
else
- name = functionNames.value(i, QStringLiteral("%qml-expression-entry"));
+ name = QStringLiteral("%qml-expression-entry");
AST::SourceElements *body;
if (function)
@@ -1290,6 +1293,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
body = body->finish();
}
+ _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups;
int idx = defineFunction(name, node,
function ? function->formals : 0,
body);
@@ -1365,15 +1369,14 @@ static V4IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpre
bool ok = false;
int value = type->enumValue(*member->name, &ok);
if (ok) {
- member->memberIsEnum = true;
- member->enumValue = value;
+ member->setEnumValue(value);
resolver->clear();
return V4IR::SInt32Type;
}
} else if (const QMetaObject *attachedMeta = type->attachedPropertiesType()) {
QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
initMetaObjectResolver(resolver, cache);
- member->attachedPropertiesId = type->attachedPropertiesId();
+ member->setAttachedPropertiesId(type->attachedPropertiesId());
return resolver->resolveMember(qmlEngine, resolver, member);
}
}
@@ -1440,8 +1443,7 @@ static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::
bool ok;
int value = metaEnum.keyToValue(enumName.constData(), &ok);
if (ok) {
- member->memberIsEnum = true;
- member->enumValue = value;
+ member->setEnumValue(value);
resolver->clear();
return V4IR::SInt32Type;
}
@@ -1533,6 +1535,9 @@ void JSCodeGen::beginFunctionBodyHook()
V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
{
+ if (_disableAcceleratedLookups)
+ return 0;
+
Q_UNUSED(line)
Q_UNUSED(col)
// Implement QML lookup semantics in the current file context.
@@ -1595,11 +1600,9 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- if (!pd->isConstant())
- _function->scopeObjectDependencies.insert(pd);
V4IR::Temp *base = _block->TEMP(_scopeObjectTemp);
initMetaObjectResolver(&base->memberResolver, _scopeObject);
- return _block->MEMBER(base, _function->newString(name), pd);
+ return _block->MEMBER(base, _function->newString(name), pd, V4IR::Member::MemberOfQmlScopeObject);
}
}
@@ -1609,11 +1612,9 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- if (!pd->isConstant())
- _function->contextObjectDependencies.insert(pd);
V4IR::Temp *base = _block->TEMP(_contextObjectTemp);
initMetaObjectResolver(&base->memberResolver, _contextObject);
- return _block->MEMBER(base, _function->newString(name), pd);
+ return _block->MEMBER(base, _function->newString(name), pd, V4IR::Member::MemberOfQmlContextObject);
}
}
@@ -1753,7 +1754,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (paramList)
paramList = paramList->finish();
- AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]);
+ AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex].node);
AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement);
AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement);
elements = elements->finish();
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index f16f910078..0a0e4f2d5b 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -166,6 +166,20 @@ struct Pragma
QV4::CompiledData::Location location;
};
+struct CompiledFunctionOrExpression
+{
+ CompiledFunctionOrExpression()
+ : disableAcceleratedLookups(false)
+ {}
+ CompiledFunctionOrExpression(AST::Node *n)
+ : node(n)
+ , disableAcceleratedLookups(false)
+ {}
+ AST::Node *node; // FunctionDeclaration, Statement or Expression
+ QString name;
+ bool disableAcceleratedLookups;
+};
+
struct ParsedQML
{
ParsedQML(bool debugMode)
@@ -180,7 +194,7 @@ struct ParsedQML
AST::UiProgram *program;
int indexOfRootObject;
QList<QmlObject*> objects;
- QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression
+ QList<CompiledFunctionOrExpression> functions;
QV4::Compiler::JSUnitGenerator jsGenerator;
QV4::CompiledData::TypeReferenceMap typeReferences;
@@ -269,7 +283,7 @@ public:
QList<QV4::CompiledData::Import*> _imports;
QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
- QList<AST::Node*> _functions;
+ QList<CompiledFunctionOrExpression> _functions;
QV4::CompiledData::TypeReferenceMap _typeReferences;
@@ -347,7 +361,7 @@ private:
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
{
- JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
+ JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports);
struct IdMapping
@@ -362,7 +376,7 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
void beginObjectScope(QQmlPropertyCache *scopeObject);
// Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions
- QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames);
+ QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
protected:
virtual void beginFunctionBodyHook();
@@ -371,12 +385,12 @@ protected:
private:
QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0);
- QQmlEnginePrivate *engine;
QString sourceCode;
QQmlJS::Engine *jsEngine; // needed for memory pool
AST::UiProgram *qmlRoot;
QQmlTypeNameCache *imports;
+ bool _disableAcceleratedLookups;
ObjectIdMapping _idObjects;
QQmlPropertyCache *_contextObject;
QQmlPropertyCache *_scopeObject;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index a8338f8656..a920f1b419 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1632,7 +1632,7 @@ bool Codegen::visit(ObjectLiteral *ast)
if (!valueMap.isEmpty()) {
V4IR::ExprList *current;
for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
- if (QV4::String(0, it.key()).asArrayIndex() != UINT_MAX) {
+ if (QV4::String::toArrayIndex(it.key()) != UINT_MAX) {
++it;
continue;
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index cb17b86702..9041b04837 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -170,20 +170,6 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
registerString(*f->formals.at(i));
for (int i = 0; i < f->locals.size(); ++i)
registerString(*f->locals.at(i));
-
- if (f->hasQmlDependencies()) {
- QSet<int> idObjectDeps = f->idObjectDependencies;
- QSet<QQmlPropertyData*> contextPropertyDeps = f->contextObjectDependencies;
- QSet<QQmlPropertyData*> scopePropertyDeps = f->scopeObjectDependencies;
-
- if (!idObjectDeps.isEmpty())
- qmlIdObjectDependenciesPerFunction.insert(f, idObjectDeps);
- if (!contextPropertyDeps.isEmpty())
- qmlContextPropertyDependenciesPerFunction.insert(f, contextPropertyDeps);
- if (!scopePropertyDeps.isEmpty())
- qmlScopePropertyDependenciesPerFunction.insert(f, scopePropertyDeps);
- }
-
}
int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
@@ -199,23 +185,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
lineNumberMappingCount = lineNumberMapping->count() / 2;
- int qmlIdDepsCount = 0;
- int qmlPropertyDepsCount = 0;
-
- if (f->hasQmlDependencies()) {
- IdDependencyHash::ConstIterator idIt = qmlIdObjectDependenciesPerFunction.find(f);
- if (idIt != qmlIdObjectDependenciesPerFunction.constEnd())
- qmlIdDepsCount += idIt->count();
-
- PropertyDependencyHash::ConstIterator it = qmlContextPropertyDependenciesPerFunction.find(f);
- if (it != qmlContextPropertyDependenciesPerFunction.constEnd())
- qmlPropertyDepsCount += it->count();
-
- it = qmlScopePropertyDependenciesPerFunction.find(f);
- if (it != qmlScopePropertyDependenciesPerFunction.constEnd())
- qmlPropertyDepsCount += it->count();
- }
-
+ const int qmlIdDepsCount = f->idObjectDependencies.count();
+ const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount, qmlIdDepsCount, qmlPropertyDepsCount);
}
@@ -353,32 +324,22 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
function->nDependingContextProperties = 0;
function->nDependingScopeProperties = 0;
- QSet<int> qmlIdObjectDeps;
- QSet<QQmlPropertyData*> qmlContextPropertyDeps;
- QSet<QQmlPropertyData*> qmlScopePropertyDeps;
-
- if (irFunction->hasQmlDependencies()) {
- qmlIdObjectDeps = qmlIdObjectDependenciesPerFunction.value(irFunction);
- qmlContextPropertyDeps = qmlContextPropertyDependenciesPerFunction.value(irFunction);
- qmlScopePropertyDeps = qmlScopePropertyDependenciesPerFunction.value(irFunction);
-
- if (!qmlIdObjectDeps.isEmpty()) {
- function->nDependingIdObjects = qmlIdObjectDeps.count();
- function->dependingIdObjectsOffset = currentOffset;
- currentOffset += function->nDependingIdObjects * sizeof(quint32);
- }
-
- if (!qmlContextPropertyDeps.isEmpty()) {
- function->nDependingContextProperties = qmlContextPropertyDeps.count();
- function->dependingContextPropertiesOffset = currentOffset;
- currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
- }
-
- if (!qmlScopePropertyDeps.isEmpty()) {
- function->nDependingScopeProperties = qmlScopePropertyDeps.count();
- function->dependingScopePropertiesOffset = currentOffset;
- currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
- }
+ if (!irFunction->idObjectDependencies.isEmpty()) {
+ function->nDependingIdObjects = irFunction->idObjectDependencies.count();
+ function->dependingIdObjectsOffset = currentOffset;
+ currentOffset += function->nDependingIdObjects * sizeof(quint32);
+ }
+
+ if (!irFunction->contextObjectPropertyDependencies.isEmpty()) {
+ function->nDependingContextProperties = irFunction->contextObjectPropertyDependencies.count();
+ function->dependingContextPropertiesOffset = currentOffset;
+ currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
+ }
+
+ if (!irFunction->scopeObjectPropertyDependencies.isEmpty()) {
+ function->nDependingScopeProperties = irFunction->scopeObjectPropertyDependencies.count();
+ function->dependingScopePropertiesOffset = currentOffset;
+ currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
}
function->location.line = irFunction->line;
@@ -407,19 +368,21 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
- foreach (int id, qmlIdObjectDeps)
+ foreach (int id, irFunction->idObjectDependencies)
*writtenDeps++ = id;
writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
- foreach (QQmlPropertyData *property, qmlContextPropertyDeps) {
- *writtenDeps++ = property->coreIndex;
- *writtenDeps++ = property->notifyIndex;
+ for (QQmlJS::V4IR::PropertyDependencyMap::ConstIterator property = irFunction->contextObjectPropertyDependencies.constBegin(), end = irFunction->contextObjectPropertyDependencies.constEnd();
+ property != end; ++property) {
+ *writtenDeps++ = property.key(); // property index
+ *writtenDeps++ = property.value(); // notify index
}
writtenDeps = (quint32 *)(f + function->dependingScopePropertiesOffset);
- foreach (QQmlPropertyData *property, qmlScopePropertyDeps) {
- *writtenDeps++ = property->coreIndex;
- *writtenDeps++ = property->notifyIndex;
+ for (QQmlJS::V4IR::PropertyDependencyMap::ConstIterator property = irFunction->scopeObjectPropertyDependencies.constBegin(), end = irFunction->scopeObjectPropertyDependencies.constEnd();
+ property != end; ++property) {
+ *writtenDeps++ = property.key(); // property index
+ *writtenDeps++ = property.value(); // notify index
}
return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries,
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 6338babb5a..1596fcb622 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -94,13 +94,6 @@ struct Q_QML_EXPORT JSUnitGenerator {
QList<QList<CompiledData::JSClassMember> > jsClasses;
uint jsClassDataSize;
uint headerSize;
-
- typedef QHash<QQmlJS::V4IR::Function *, QSet<int> > IdDependencyHash;
- IdDependencyHash qmlIdObjectDependenciesPerFunction;
-
- typedef QHash<QQmlJS::V4IR::Function *, QSet<QQmlPropertyData*> > PropertyDependencyHash;
- PropertyDependencyHash qmlContextPropertyDependenciesPerFunction;
- PropertyDependencyHash qmlScopePropertyDependenciesPerFunction;
};
}
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 67c4f672c6..35097bae49 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -68,7 +68,7 @@ using namespace QV4;
CompilationUnit::~CompilationUnit()
{
foreach (Function *f, runtimeFunctions)
- engine->allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr));
+ engine->allFunctions.remove(reinterpret_cast<quintptr>(f->code));
}
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
@@ -85,7 +85,7 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
foreach (Function *f, runtimeFunctions)
- engine->allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f);
+ engine->allFunctions.insert(reinterpret_cast<quintptr>(f->code), f);
}
QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex)
@@ -2494,11 +2494,10 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->and32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->and32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
case V4IR::OpBitOr: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
@@ -2515,11 +2514,10 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->or32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->or32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
case V4IR::OpBitXor: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
@@ -2536,32 +2534,41 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->xor32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->xor32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
- case V4IR::OpLShift:
+ case V4IR::OpLShift: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
- _as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::ReturnValueRegister);
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
_as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
_as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); // TODO: for constants, do this in the IR
- _as->lshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->lshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister,
+ Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
- return true;
- case V4IR::OpRShift:
+ } return true;
+ case V4IR::OpRShift: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
- _as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::ReturnValueRegister);
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
_as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
_as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); // TODO: for constants, do this in the IR
- _as->rshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->rshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister,
+ Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
- return true;
+ } return true;
case V4IR::OpURShift:
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
_as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
@@ -2572,6 +2579,58 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
_as->urshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
_as->storeUInt32(Assembler::ReturnValueRegister, target);
return true;
+ case V4IR::OpAdd: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->add32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
+ case V4IR::OpSub: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister
+ && target->kind == V4IR::Temp::PhysicalRegister
+ && target->index == rightSource->asTemp()->index) {
+ Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index;
+ _as->move(targetReg, Assembler::ScratchRegister);
+ _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
+ _as->sub32(Assembler::ScratchRegister, targetReg);
+ _as->storeInt32(targetReg, target);
+ return true;
+ }
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
+ _as->sub32(_as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
+ case V4IR::OpMul: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->mul32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
default:
return false;
}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index f7987aac5c..f5d4e469e5 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -1039,7 +1039,6 @@ public:
static const BinaryOperationInfo &binaryOperation(V4IR::AluOp operation)
{ return binaryOperations[operation]; }
-
Jump inline_add32(Address addr, RegisterID reg)
{
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 7f0d8313fe..b86837e167 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -148,11 +148,20 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->source->asMember()) {
if (m->property) {
bool captureRequired = true;
- if (_function && m->attachedPropertiesId == 0) {
- captureRequired = !_function->contextObjectDependencies.contains(m->property)
- && !_function->scopeObjectDependencies.contains(m->property);
+
+ Q_ASSERT(m->kind != V4IR::Member::MemberOfEnum);
+ const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
+
+ if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
+ if (m->kind == V4IR::Member::MemberOfQmlContextObject) {
+ _function->contextObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ captureRequired = false;
+ } else if (m->kind == V4IR::Member::MemberOfQmlScopeObject) {
+ _function->scopeObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ captureRequired = false;
+ }
}
- getQObjectProperty(m->base, m->property->coreIndex, captureRequired, m->attachedPropertiesId, t);
+ getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t);
return;
} else if (m->base->asTemp() || m->base->asConst()) {
getProperty(m->base, *m->name, t);
@@ -191,7 +200,9 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->target->asMember()) {
if (m->base->asTemp() || m->base->asConst()) {
if (s->source->asTemp() || s->source->asConst()) {
- if (m->property && m->attachedPropertiesId == 0) {
+ Q_ASSERT(m->kind != V4IR::Member::MemberOfEnum);
+ const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
+ if (m->property && attachedPropertiesId == 0) {
setQObjectProperty(s->source, m->base, m->property->coreIndex);
return;
} else {
@@ -230,9 +241,7 @@ void IRDecoder::visitExp(V4IR::Exp *s)
Q_ASSERT(member->base->asTemp());
callProperty(member->base->asTemp(), *member->name, c->args, 0);
} else if (Subscript *s = c->base->asSubscript()) {
- Q_ASSERT(s->base->asTemp());
- Q_ASSERT(s->index->asTemp());
- callSubscript(s->base->asTemp(), s->index->asTemp(), c->args, 0);
+ callSubscript(s->base, s->index, c->args, 0);
} else {
Q_UNIMPLEMENTED();
}
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index a2dbf44375..deb1af51b4 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -554,8 +554,8 @@ void Subscript::dump(QTextStream &out) const
void Member::dump(QTextStream &out) const
{
- if (attachedPropertiesId != 0 && !base->asTemp())
- out << "[[attached property from " << attachedPropertiesId << "]]";
+ if (kind != MemberOfEnum && attachedPropertiesIdOrEnumValue != 0 && !base->asTemp())
+ out << "[[attached property from " << attachedPropertiesIdOrEnumValue << "]]";
else
base->dump(out);
out << '.' << *name;
@@ -843,17 +843,10 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
return e;
}
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, int attachedPropertiesId)
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
{
Member*e = function->New<Member>();
- e->init(base, name, property, attachedPropertiesId);
- return e;
-}
-
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name, int enumValue)
-{
- Member*e = function->New<Member>();
- e->init(base, name, enumValue);
+ e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
return e;
}
@@ -1044,10 +1037,7 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
Expr *clonedBase = clone(e->base);
- if (e->memberIsEnum)
- cloned = block->MEMBER(clonedBase, e->name, e->enumValue);
- else
- cloned = block->MEMBER(clonedBase, e->name, e->property, e->attachedPropertiesId);
+ cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 59e8d02bbc..2eba3405fe 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -554,42 +554,49 @@ struct Subscript: Expr {
};
struct Member: Expr {
+ // Used for property dependency tracking
+ enum MemberKind {
+ UnspecifiedMember,
+ MemberOfEnum,
+ MemberOfQmlScopeObject,
+ MemberOfQmlContextObject
+ };
+
Expr *base;
const QString *name;
QQmlPropertyData *property;
- int attachedPropertiesId;
- int enumValue;
- bool memberIsEnum : 1;
- bool freeOfSideEffects : 1;
+ int attachedPropertiesIdOrEnumValue; // depending on kind
+ uchar memberIsEnum : 1;
+ uchar freeOfSideEffects : 1;
// This is set for example for for QObject properties. All sorts of extra behavior
// is defined when writing to them, for example resettable properties are reset
// when writing undefined to them, and an exception is thrown when they're missing
// a reset function. And then there's also Qt.binding().
- bool inhibitTypeConversionOnWrite: 1;
+ uchar inhibitTypeConversionOnWrite: 1;
- void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, int attachedPropertiesId = 0)
+ uchar kind: 3; // MemberKind
+
+ void setEnumValue(int value) {
+ kind = MemberOfEnum;
+ attachedPropertiesIdOrEnumValue = value;
+ }
+
+ void setAttachedPropertiesId(int id) {
+ Q_ASSERT(kind != MemberOfEnum);
+ attachedPropertiesIdOrEnumValue = id;
+ }
+
+ void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0)
{
this->base = base;
this->name = name;
this->property = property;
- this->attachedPropertiesId = attachedPropertiesId;
- this->enumValue = 0;
+ this->attachedPropertiesIdOrEnumValue = attachedPropertiesIdOrEnumValue;
this->memberIsEnum = false;
this->freeOfSideEffects = false;
this->inhibitTypeConversionOnWrite = property != 0;
- }
-
- void init(Expr *base, const QString *name, int enumValue)
- {
- this->base = base;
- this->name = name;
- this->property = 0;
- this->attachedPropertiesId = 0;
- this->enumValue = enumValue;
- this->memberIsEnum = true;
- this->freeOfSideEffects = false;
- this->inhibitTypeConversionOnWrite = false;
+ this->kind = kind;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
@@ -752,6 +759,9 @@ struct Q_QML_EXPORT Module {
void setFileName(const QString &name);
};
+// Map from meta property index (existence implies dependency) to notify signal index
+typedef QHash<int, int> PropertyDependencyMap;
+
struct Function {
Module *module;
MemoryPool *pool;
@@ -782,10 +792,8 @@ struct Function {
// Qml extension:
QSet<int> idObjectDependencies;
- QSet<QQmlPropertyData*> contextObjectDependencies;
- QSet<QQmlPropertyData*> scopeObjectDependencies;
-
- bool hasQmlDependencies() const { return !idObjectDependencies.isEmpty() || !contextObjectDependencies.isEmpty() || !scopeObjectDependencies.isEmpty(); }
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
@@ -895,8 +903,7 @@ struct BasicBlock {
Expr *CALL(Expr *base, ExprList *args = 0);
Expr *NEW(Expr *base, ExprList *args = 0);
Expr *SUBSCRIPT(Expr *base, Expr *index);
- Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0, int attachedPropertiesId = 0);
- Expr *MEMBER(Expr *base, const QString *name, int enumValue);
+ Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = Member::UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0);
Stmt *EXP(Expr *expr);
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 5d341ed149..93ecdb2602 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -518,8 +518,15 @@ protected: // IRDecoder
|| (oper >= OpGt && oper <= OpStrictNotEqual)) {
needsCall = false;
}
- } if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
+ } else if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
needsCall = false;
+ } else if (oper == OpAdd
+ || oper == OpMul
+ ||
+ oper == OpSub
+ ) {
+ if (leftSource->type == SInt32Type && rightSource->type == SInt32Type)
+ needsCall = false;
}
addDef(target);
@@ -897,9 +904,9 @@ private:
}
}
if (!moveFrom) {
- Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole);
Q_UNUSED(lifeTimeHole);
#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole);
if (_info->def(it.temp()) != successorStart && !it.isSplitFromInterval()) {
const int successorEnd = successor->statements.last()->id;
const int idx = successor->in.indexOf(predecessor);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 249dfab660..b3eb6835df 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -213,6 +213,48 @@ void showMeTheCode(Function *function)
}
}
+class ProcessedBlocks
+{
+ QBitArray processed;
+
+public:
+ ProcessedBlocks(const QVector<BasicBlock *> allBlocks)
+ {
+ int maxBB = 0;
+ foreach (BasicBlock *bb, allBlocks)
+ maxBB = qMax(maxBB, bb->index);
+ processed = QBitArray(maxBB + 1, false);
+ }
+
+ bool alreadyProcessed(BasicBlock *bb) const
+ {
+ Q_ASSERT(bb);
+
+ return processed.at(bb->index);
+ }
+
+ void markAsProcessed(BasicBlock *bb)
+ {
+ processed.setBit(bb->index);
+ }
+};
+
+inline Temp *unescapableTemp(Expr *e, bool variablesCanEscape)
+{
+ Temp *t = e->asTemp();
+ if (!t)
+ return 0;
+
+ switch (t->kind) {
+ case Temp::VirtualRegister:
+ return t;
+ case Temp::Local:
+ return variablesCanEscape ? 0 : t;
+ default:
+ return 0;
+ }
+}
+
class DominatorTree {
int N;
QHash<BasicBlock *, int> dfnum;
@@ -353,15 +395,6 @@ class DominatorTree {
#endif // SHOW_SSA
}
- bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
- for (BasicBlock *it = dominated; it; it = idom[it]) {
- if (it == dominator)
- return true;
- }
-
- return false;
- }
-
struct NodeProgress {
QSet<BasicBlock *> children;
QSet<BasicBlock *> todo;
@@ -474,6 +507,15 @@ public:
BasicBlock *immediateDominator(BasicBlock *bb) const {
return idom[bb];
}
+
+ bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
+ for (BasicBlock *it = dominated; it; it = idom[it]) {
+ if (it == dominator)
+ return true;
+ }
+
+ return false;
+ }
};
class VariableCollector: public StmtVisitor, ExprVisitor {
@@ -626,15 +668,86 @@ void insertPhiNode(const Temp &a, BasicBlock *y, Function *f) {
}
}
+// High-level (recursive) algorithm:
+// Mapping: old temp number -> new temp number
+//
+// Start:
+// Rename(start-node)
+//
+// Rename(node, mapping):
+// for each statement S in block n
+// if S not in a phi-function
+// for each use of some variable x in S
+// y = mapping[x]
+// replace the use of x with y in S
+// for each definition of some variable a in S [1]
+// a_new = generate new/unique temp
+// mapping[a] = a_new
+// replace definition of a with definition of a_new in S
+// for each successor Y of block n
+// Suppose n is the j-th predecessor of Y
+// for each phi function in Y
+// suppose the j-th operand of the phi-function is a
+// i = mapping[a]
+// replace the j-th operand with a_i
+// for each child X of n [2]
+// Rename(X)
+// for each newly generated temp from step [1] restore the old value [3]
+//
+// This algorithm can run out of CPU stack space when there are lots of basic-blocks, like in a
+// switch statement with 8000 cases that all fall-through. The iterativer version below uses a
+// work-item stack, where step [1] from the algorithm above also pushes an "undo mapping change",
+// and step [2] pushes a "rename(X)" action. This eliminates step [3].
+//
+// Iterative version:
+// Mapping: old temp number -> new temp number
+//
+// The stack can hold two kinds of actions:
+// "Rename basic block n"
+// "Restore count for temp"
+//
+// Start:
+// counter = 0
+// push "Rename start node" onto the stack
+// while the stack is not empty:
+// take the last item, and process it
+//
+// Rename(n) =
+// for each statement S in block n
+// if S not in a phi-function
+// for each use of some variable x in S
+// y = mapping[x]
+// replace the use of x with y in S
+// for each definition of some variable a in S
+// old = mapping[a]
+// push Undo(a, old)
+// counter = counter + 1
+// new = counter;
+// mapping[a] = new
+// replace definition of a with definition of a_new in S
+// for each successor Y of block n
+// Suppose n is the j-th predecessor of Y
+// for each phi function in Y
+// suppose the j-th operand of the phi-function is a
+// i = mapping[a]
+// replace the j-th operand with a_i
+// for each child X of n
+// push Rename(X)
+//
+// Undo(t, c) =
+// mapping[t] = c
class VariableRenamer: public StmtVisitor, public ExprVisitor
{
Function *function;
- QHash<Temp, QStack<unsigned> > stack;
- QSet<BasicBlock *> seen;
+ const bool variablesCanEscape;
+ unsigned tempCount;
- QHash<Temp, unsigned> defCounts;
+ typedef QHash<unsigned, int> Mapping; // maps from existing/old temp number to the new and unique temp number.
+ enum { Absent = -1 };
+ Mapping localMapping;
+ Mapping vregMapping;
+ ProcessedBlocks processed;
- const bool variablesCanEscape;
bool isRenamable(Temp *t) const
{
switch (t->kind) {
@@ -651,99 +764,122 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor
return false;
}
}
- int nextFreeTemp() {
- const int next = function->tempCount++;
-// qDebug()<<"Next free temp:"<<next;
- return next;
- }
-
- /*
-
- Initialization:
- for each variable a
- count[a] = 0;
- stack[a] = empty;
- push 0 onto stack
-
- Rename(n) =
- for each statement S in block n [1]
- if S not in a phi-function
- for each use of some variable x in S
- i = top(stack[x])
- replace the use of x with x_i in S
- for each definition of some variable a in S
- count[a] = count[a] + 1
- i = count[a]
- push i onto stack[a]
- replace definition of a with definition of a_i in S
- for each successor Y of block n [2]
- Suppose n is the j-th predecessor of Y
- for each phi function in Y
- suppose the j-th operand of the phi-function is a
- i = top(stack[a])
- replace the j-th operand with a_i
- for each child X of n [3]
- Rename(X)
- for each statement S in block n [4]
- for each definition of some variable a in S
- pop stack[a]
-
- */
+
+ struct TodoAction {
+ enum { RestoreLocal, RestoreVReg, Rename } action;
+ union {
+ struct {
+ unsigned temp;
+ int previous;
+ } restoreData;
+ struct {
+ BasicBlock *basicBlock;
+ } renameData;
+ };
+
+ bool isValid() const { return action != Rename || renameData.basicBlock != 0; }
+
+ TodoAction()
+ {
+ action = Rename;
+ renameData.basicBlock = 0;
+ }
+
+ TodoAction(const Temp &t, int prev)
+ {
+ Q_ASSERT(t.kind == Temp::Local || t.kind == Temp::VirtualRegister);
+
+ action = t.kind == Temp::Local ? RestoreLocal : RestoreVReg;
+ restoreData.temp = t.index;
+ restoreData.previous = prev;
+ }
+
+ TodoAction(BasicBlock *bb)
+ {
+ Q_ASSERT(bb);
+
+ action = Rename;
+ renameData.basicBlock = bb;
+ }
+ };
+
+ QVector<TodoAction> todo;
public:
VariableRenamer(Function *f)
: function(f)
, variablesCanEscape(f->variablesCanEscape())
+ , tempCount(0)
+ , processed(f->basicBlocks)
{
- if (!variablesCanEscape) {
- Temp t;
- t.init(Temp::Local, 0, 0);
- for (int i = 0, ei = f->locals.size(); i != ei; ++i) {
- t.index = i;
- stack[t].push(nextFreeTemp());
+ }
+
+ void run() {
+ todo.append(TodoAction(function->basicBlocks.first()));
+
+ while (!todo.isEmpty()) {
+ TodoAction todoAction = todo.back();
+ Q_ASSERT(todoAction.isValid());
+ todo.pop_back();
+
+ switch (todoAction.action) {
+ case TodoAction::Rename:
+ rename(todoAction.renameData.basicBlock);
+ break;
+ case TodoAction::RestoreLocal:
+ restore(localMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
+ break;
+ case TodoAction::RestoreVReg:
+ restore(vregMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
+ break;
+ default:
+ Q_UNREACHABLE();
}
}
- Temp t;
- t.init(Temp::VirtualRegister, 0, 0);
- for (int i = 0, ei = f->tempCount; i != ei; ++i) {
- t.index = i;
- stack[t].push(i);
- }
+ function->tempCount = tempCount;
}
- void run() {
- foreach (BasicBlock *n, function->basicBlocks)
- rename(n);
-
-#ifdef SHOW_SSA
-// qout << "Temp to local mapping:" << endl;
-// foreach (int key, tempMapping.keys())
-// qout << '\t' << key << " -> " << tempMapping[key] << endl;
-#endif
+private:
+ static inline void restore(Mapping &mapping, unsigned temp, int previous)
+ {
+ if (previous == Absent)
+ mapping.remove(temp);
+ else
+ mapping[temp] = previous;
}
- void rename(BasicBlock *n) {
- if (seen.contains(n))
- return;
- seen.insert(n);
-// qDebug() << "I: L"<<n->index;
+ void rename(BasicBlock *bb)
+ {
+ while (bb && !processed.alreadyProcessed(bb)) {
+ renameStatementsAndPhis(bb);
+ processed.markAsProcessed(bb);
- // [1]:
- foreach (Stmt *s, n->statements)
- s->accept(this);
+ BasicBlock *next = 0;
+ foreach (BasicBlock *out, bb->out) {
+ if (processed.alreadyProcessed(out))
+ continue;
+ if (!next)
+ next = out;
+ else
+ todo.append(TodoAction(out));
+ }
+ bb = next;
+ }
+ }
- QHash<Temp, unsigned> dc = defCounts;
- defCounts.clear();
+ void renameStatementsAndPhis(BasicBlock *bb)
+ {
+ foreach (Stmt *s, bb->statements)
+ s->accept(this);
- // [2]:
- foreach (BasicBlock *Y, n->out) {
- const int j = Y->in.indexOf(n);
+ foreach (BasicBlock *Y, bb->out) {
+ const int j = Y->in.indexOf(bb);
Q_ASSERT(j >= 0 && j < Y->in.size());
foreach (Stmt *s, Y->statements) {
if (Phi *phi = s->asPhi()) {
Temp *t = phi->d->incoming[j]->asTemp();
- unsigned newTmp = stack[*t].top();
+ unsigned newTmp = currentNumber(*t);
// qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index;
t->index = newTmp;
t->kind = Temp::VirtualRegister;
@@ -752,24 +888,65 @@ public:
}
}
}
+ }
+
+ unsigned currentNumber(const Temp &t)
+ {
+ int nr = Absent;
+ switch (t.kind) {
+ case Temp::Local:
+ nr = localMapping.value(t.index, Absent);
+ break;
+ case Temp::VirtualRegister:
+ nr = vregMapping.value(t.index, Absent);
+ break;
+ default:
+ Q_UNREACHABLE();
+ nr = Absent;
+ break;
+ }
+ if (nr == Absent) {
+ // Special case: we didn't prune the Phi nodes yet, so for proper temps (virtual
+ // registers) the SSA algorithm might insert superfluous Phis that have uses without
+ // definition. E.g.: if a temporary got introduced in the "then" clause, it "could"
+ // reach the "end-if" block, so there will be a phi node for that temp. A later pass
+ // will clean this up by looking for uses-without-defines in phi nodes. So, what we do
+ // is to generate a new unique number, and leave it dangling.
+ nr = nextFreeTemp(t);
+ }
- // [3]:
- foreach (BasicBlock *X, n->out)
- rename(X);
+ return nr;
+ }
+
+ unsigned nextFreeTemp(const Temp &t)
+ {
+ unsigned newIndex = tempCount++;
+ Q_ASSERT(newIndex <= INT_MAX);
+ int oldIndex = Absent;
- // [4]:
- for (QHash<Temp, unsigned>::const_iterator i = dc.begin(), ei = dc.end(); i != ei; ++i) {
-// qDebug()<<i.key() <<" -> " << i.value();
- for (unsigned j = 0, ej = i.value(); j < ej; ++j)
- stack[i.key()].pop();
+ switch (t.kind) {
+ case Temp::Local:
+ oldIndex = localMapping.value(t.index, Absent);
+ localMapping.insert(t.index, newIndex);
+ break;
+ case Temp::VirtualRegister:
+ oldIndex = vregMapping.value(t.index, Absent);
+ vregMapping.insert(t.index, newIndex);
+ break;
+ default:
+ Q_UNREACHABLE();
}
+
+ todo.append(TodoAction(t, oldIndex));
+
+ return newIndex;
}
protected:
virtual void visitTemp(Temp *e) { // only called for uses, not defs
if (isRenamable(e)) {
// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
- e->index = stack[*e].top();
+ e->index = currentNumber(*e);
e->kind = Temp::VirtualRegister;
}
}
@@ -787,9 +964,7 @@ protected:
void renameTemp(Temp *t) {
if (isRenamable(t)) {
- defCounts[*t] = defCounts.value(*t, 0) + 1;
- const int newIdx = nextFreeTemp();
- stack[*t].push(newIdx);
+ const int newIdx = nextFreeTemp(*t);
// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
t->kind = Temp::VirtualRegister;
t->index = newIdx;
@@ -875,12 +1050,15 @@ void convertToSSA(Function *function, const DominatorTree &df)
struct UntypedTemp {
Temp temp;
+ UntypedTemp() {}
UntypedTemp(const Temp &t): temp(t) {}
};
inline uint qHash(const UntypedTemp &t, uint seed = 0) Q_DECL_NOTHROW
{ return t.temp.index ^ (t.temp.kind | (t.temp.scope << 3)) ^ seed; }
inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
{ return t1.temp.index == t2.temp.index && t1.temp.scope == t2.temp.scope && t1.temp.kind == t2.temp.kind; }
+inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
+{ return !(t1 == t2); }
class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
public:
@@ -965,6 +1143,8 @@ public:
defUse.blockOfStatement = defBlock;
}
+ QList<UntypedTemp> defsUntyped() const { return _defUses.keys(); }
+
QList<Temp> defs() const {
QList<Temp> res;
res.reserve(_defUses.size());
@@ -983,10 +1163,10 @@ public:
void addUse(const Temp &variable, Stmt * newUse)
{ _defUses[variable].uses.append(newUse); }
- int useCount(const Temp &variable) const
+ int useCount(const UntypedTemp &variable) const
{ return _defUses[variable].uses.size(); }
- Stmt *defStmt(const Temp &variable) const
+ Stmt *defStmt(const UntypedTemp &variable) const
{ return _defUses[variable].defStmt; }
BasicBlock *defStmtBlock(const Temp &variable) const
@@ -998,7 +1178,7 @@ public:
QList<Temp> usedVars(Stmt *s) const
{ return _usesPerStatement[s]; }
- QList<Stmt *> uses(const Temp &var) const
+ QList<Stmt *> uses(const UntypedTemp &var) const
{ return _defUses[var].uses; }
QVector<Stmt*> removeDefUses(Stmt *s)
@@ -1280,25 +1460,97 @@ protected:
}
};
-class TypeInference: public StmtVisitor, public ExprVisitor {
- struct DiscoveredType {
- int type;
- MemberExpressionResolver memberResolver;
-
- DiscoveredType() : type(UnknownType) {}
- DiscoveredType(Type t) : type(t) { Q_ASSERT(type != QObjectType); }
- explicit DiscoveredType(int t) : type(t) { Q_ASSERT(type != QObjectType); }
- explicit DiscoveredType(MemberExpressionResolver memberResolver) : type(QObjectType), memberResolver(memberResolver) {}
-
- bool test(Type t) const { return type & t; }
- bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
-
- bool operator!=(Type other) const { return type != other; }
- bool operator==(Type other) const { return type == other; }
- bool operator==(const DiscoveredType &other) const { return type == other.type; }
- bool operator!=(const DiscoveredType &other) const { return type != other.type; }
- };
+struct DiscoveredType {
+ int type;
+ MemberExpressionResolver memberResolver;
+
+ DiscoveredType() : type(UnknownType) {}
+ DiscoveredType(Type t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(int t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(MemberExpressionResolver memberResolver) : type(QObjectType), memberResolver(memberResolver) {}
+
+ bool test(Type t) const { return type & t; }
+ bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
+
+ bool operator!=(Type other) const { return type != other; }
+ bool operator==(Type other) const { return type == other; }
+ bool operator==(const DiscoveredType &other) const { return type == other.type; }
+ bool operator!=(const DiscoveredType &other) const { return type != other.type; }
+};
+
+class PropagateTempTypes: public StmtVisitor, ExprVisitor
+{
+ const DefUsesCalculator &defUses;
+ UntypedTemp theTemp;
+ DiscoveredType newType;
+
+public:
+ PropagateTempTypes(const DefUsesCalculator &defUses)
+ : defUses(defUses)
+ {}
+
+ void run(const UntypedTemp &temp, const DiscoveredType &type)
+ {
+ newType = type;
+ theTemp = temp;
+ if (Stmt *defStmt = defUses.defStmt(temp))
+ defStmt->accept(this);
+ foreach (Stmt *use, defUses.uses(temp))
+ use->accept(this);
+ }
+
+protected:
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *e) {
+ if (theTemp == UntypedTemp(*e)) {
+ e->type = static_cast<Type>(newType.type);
+ e->memberResolver = newType.memberResolver;
+ }
+ }
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitSubscript(Subscript *e) {
+ e->base->accept(this);
+ e->index->accept(this);
+ }
+
+ virtual void visitMember(Member *e) {
+ e->base->accept(this);
+ }
+
+ virtual void visitExp(Exp *s) {s->expr->accept(this);}
+ virtual void visitMove(Move *s) {
+ s->source->accept(this);
+ s->target->accept(this);
+ }
+
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitPhi(Phi *s) {
+ s->targetTemp->accept(this);
+ foreach (Expr *e, s->d->incoming)
+ e->accept(this);
+ }
+};
+class TypeInference: public StmtVisitor, public ExprVisitor {
QQmlEnginePrivate *qmlEngine;
bool _variablesCanEscape;
const DefUsesCalculator &_defUses;
@@ -1355,78 +1607,12 @@ public:
}
}
- PropagateTempTypes(_tempTypes).run(function);
+ PropagateTempTypes propagator(_defUses);
+ for (QHash<Temp, DiscoveredType>::const_iterator i = _tempTypes.begin(), ei = _tempTypes.end(); i != ei; ++i)
+ propagator.run(i.key(), i.value());
}
private:
- class PropagateTempTypes: public StmtVisitor, ExprVisitor
- {
- public:
- PropagateTempTypes(const QHash<Temp, DiscoveredType> &tempTypes)
- : _tempTypes(tempTypes)
- {}
-
- void run(Function *function)
- {
- foreach (BasicBlock *bb, function->basicBlocks)
- foreach (Stmt *s, bb->statements)
- s->accept(this);
- }
-
- protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(String *) {}
- virtual void visitRegExp(RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) {
- DiscoveredType t = _tempTypes[*e];
- e->type = (Type) t.type;
- e->memberResolver = t.memberResolver;
- }
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
-
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
- virtual void visitSubscript(Subscript *e) {
- e->base->accept(this);
- e->index->accept(this);
- }
-
- virtual void visitMember(Member *e) {
- e->base->accept(this);
- }
-
- virtual void visitExp(Exp *s) {s->expr->accept(this);}
- virtual void visitMove(Move *s) {
- s->source->accept(this);
- s->target->accept(this);
- }
-
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *s) {
- s->targetTemp->accept(this);
- foreach (Expr *e, s->d->incoming)
- e->accept(this);
- }
-
- private:
- QHash<Temp, DiscoveredType> _tempTypes;
- };
-
-private:
bool run(Stmt *s) {
TypingResult ty;
std::swap(_ty, ty);
@@ -1446,13 +1632,16 @@ private:
return ty;
}
- bool isAlwaysAnObject(Temp *t) {
+ bool isAlwaysVar(Temp *t) {
switch (t->kind) {
case Temp::Formal:
case Temp::ScopedFormal:
case Temp::ScopedLocal:
+ t->type = VarType;
return true;
case Temp::Local:
+ if (_variablesCanEscape)
+ t->type = VarType;
return _variablesCanEscape;
default:
return false;
@@ -1464,7 +1653,7 @@ private:
#if defined(SHOW_SSA)
qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
#endif
- if (isAlwaysAnObject(t))
+ if (isAlwaysVar(t))
ty = DiscoveredType(VarType);
if (_tempTypes[*t] != ty) {
_tempTypes[*t] = ty;
@@ -1500,7 +1689,7 @@ protected:
virtual void visitRegExp(RegExp *) { _ty = TypingResult(VarType); }
virtual void visitName(Name *) { _ty = TypingResult(VarType); }
virtual void visitTemp(Temp *e) {
- if (isAlwaysAnObject(e))
+ if (isAlwaysVar(e))
_ty = TypingResult(VarType);
else if (e->memberResolver.isValid())
_ty = TypingResult(e->memberResolver);
@@ -1677,6 +1866,147 @@ protected:
}
};
+class ReverseInference
+{
+ const DefUsesCalculator &_defUses;
+ bool _variablesCanExcape;
+
+public:
+ ReverseInference(const DefUsesCalculator &defUses)
+ : _defUses(defUses)
+ {}
+
+ void run(Function *f)
+ {
+ _variablesCanExcape = f->variablesCanEscape();
+
+ QTextStream os(stderr, QIODevice::WriteOnly);
+
+ QVector<UntypedTemp> knownOk;
+ QList<UntypedTemp> candidates = _defUses.defsUntyped();
+ while (!candidates.isEmpty()) {
+ UntypedTemp temp = candidates.last();
+ candidates.removeLast();
+
+ if (knownOk.contains(temp))
+ continue;
+
+ if (!isUsedAsInt32(temp, knownOk))
+ continue;
+
+ Stmt *s = _defUses.defStmt(temp);
+ Move *m = s->asMove();
+ if (!m)
+ continue;
+ Temp *target = m->target->asTemp();
+ if (!target || temp != UntypedTemp(*target) || target->type == SInt32Type)
+ continue;
+ if (Temp *t = m->source->asTemp()) {
+ candidates.append(*t);
+ } else if (m->source->asConvert()) {
+ break;
+ } else if (Binop *b = m->source->asBinop()) {
+ switch (b->op) {
+ case OpAdd:
+ if (b->left->type & NumberType || b->right->type & NumberType)
+ break;
+ else
+ continue;
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpSub:
+ case OpMul:
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ break;
+ default:
+ continue;
+ }
+ if (Temp *lt = unescapableTemp(b->left, _variablesCanExcape))
+ candidates.append(*lt);
+ if (Temp *rt = unescapableTemp(b->right, _variablesCanExcape))
+ candidates.append(*rt);
+ } else if (Unop *u = m->source->asUnop()) {
+ if (u->op == OpCompl || u->op == OpUPlus) {
+ if (Temp *t = unescapableTemp(u->expr, _variablesCanExcape))
+ candidates.append(*t);
+ }
+ } else {
+ continue;
+ }
+
+ knownOk.append(temp);
+ }
+
+ PropagateTempTypes propagator(_defUses);
+ foreach (const UntypedTemp &t, knownOk) {
+ propagator.run(t, SInt32Type);
+ if (Stmt *defStmt = _defUses.defStmt(t)) {
+ if (Move *m = defStmt->asMove()) {
+ if (Convert *c = m->source->asConvert())
+ c->type = SInt32Type;
+ else if (Unop *u = m->source->asUnop())
+ u->type = SInt32Type;
+ else if (Binop *b = m->source->asBinop())
+ b->type = SInt32Type;
+ }
+ }
+ }
+ }
+
+private:
+ bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
+ {
+ QList<Stmt *> uses = _defUses.uses(t);
+ if (uses.isEmpty())
+ return false;
+
+ foreach (Stmt *use, uses) {
+ if (Move *m = use->asMove()) {
+ Temp *targetTemp = m->target->asTemp();
+
+ if (m->source->asTemp()) {
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ } else if (m->source->asConvert()) {
+ continue;
+ } else if (Binop *b = m->source->asBinop()) {
+ switch (b->op) {
+ case OpAdd:
+ case OpSub:
+ case OpMul:
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpRShift:
+ case OpLShift:
+ case OpURShift:
+ continue;
+ default:
+ return false;
+ }
+ } else if (Unop *u = m->source->asUnop()) {
+ if (u->op == OpUPlus) {
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ } else if (u->op != OpCompl) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else
+ return false;
+ }
+
+ return true;
+ }
+};
+
void convertConst(Const *c, Type targetType)
{
switch (targetType) {
@@ -1932,13 +2262,16 @@ void splitCriticalEdges(Function *f)
for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
BasicBlock *inBB = bb->in[inIdx];
if (inBB->out.size() > 1) { // this should have been split!
+ int newIndex = f->basicBlocks.last()->index + 1;
#if defined(SHOW_SSA)
- qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index;
+ qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex;
#endif
+ BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
+
// create the basic block:
- BasicBlock *newBB = new BasicBlock(f, bb->containingGroup(), bb->catchBlock);
- newBB->index = f->basicBlocks.last()->index + 1;
+ BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock);
+ newBB->index = newIndex;
f->basicBlocks.append(newBB);
Jump *s = f->New<Jump>();
s->init(bb);
@@ -1974,84 +2307,153 @@ void splitCriticalEdges(Function *f)
}
}
-QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const DominatorTree &df)
+// 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 smae reason.
+class BlockScheduler
{
- struct I {
- const DominatorTree &df;
- QHash<BasicBlock *, BasicBlock *> &startEndLoops;
- QSet<BasicBlock *> visited;
- QVector<BasicBlock *> &sequence;
- BasicBlock *currentGroup;
- QList<BasicBlock *> postponed;
-
- I(const DominatorTree &df, QVector<BasicBlock *> &sequence,
- QHash<BasicBlock *, BasicBlock *> &startEndLoops)
- : df(df)
- , startEndLoops(startEndLoops)
- , sequence(sequence)
- , currentGroup(0)
- {}
+ Function *function;
+ const DominatorTree &dominatorTree;
- void DFS(BasicBlock *bb) {
- Q_ASSERT(bb);
- if (visited.contains(bb))
- return;
+ struct WorkForGroup
+ {
+ BasicBlock *group;
+ QStack<BasicBlock *> postponed;
- if (bb->containingGroup() != currentGroup) {
- postponed.append(bb);
- return;
- }
- if (bb->isGroupStart())
- currentGroup = bb;
- else if (bb->in.size() > 1)
- foreach (BasicBlock *inBB, bb->in)
- if (!visited.contains(inBB))
- return;
-
- Q_ASSERT(df.immediateDominator(bb) == 0 || sequence.contains(df.immediateDominator(bb)));
- layout(bb);
- if (Stmt *terminator = bb->terminator()) {
- if (Jump *j = terminator->asJump()) {
- Q_ASSERT(bb->out.size() == 1);
- DFS(j->target);
- } else if (CJump *cj = terminator->asCJump()) {
- Q_ASSERT(bb->out.size() == 2);
- DFS(cj->iftrue);
- DFS(cj->iffalse);
- } else if (terminator->asRet()) {
- Q_ASSERT(bb->out.size() == 0);
- // nothing to do.
- } else {
- Q_UNREACHABLE();
- }
- } else {
- Q_UNREACHABLE();
+ WorkForGroup(BasicBlock *group = 0): group(group) {}
+ };
+ WorkForGroup currentGroup;
+ QStack<WorkForGroup> postponedGroups;
+ QVector<BasicBlock *> sequence;
+ ProcessedBlocks emitted;
+ QHash<BasicBlock *, BasicBlock *> loopsStartEnd;
+
+ bool checkCandidate(BasicBlock *candidate)
+ {
+ Q_ASSERT(candidate->containingGroup() == currentGroup.group);
+
+ foreach (BasicBlock *in, candidate->in) {
+ if (emitted.alreadyProcessed(in))
+ continue;
+
+ // this is a loop, where there in -> candidate edge is the jump back to the top of the loop.
+ if (dominatorTree.dominates(candidate, in))
+ continue;
+
+ return false; // an incoming edge that is not yet emitted, and is not a back-edge
+ }
+
+ // postpone everything, and schedule the loop first.
+ if (candidate->isGroupStart()) {
+ postponedGroups.push(currentGroup);
+ currentGroup = WorkForGroup(candidate);
+ }
+
+ return true;
+ }
+
+ BasicBlock *pickNext()
+ {
+ while (true) {
+ while (currentGroup.postponed.isEmpty()) {
+ if (postponedGroups.isEmpty())
+ return 0;
+ if (currentGroup.group) // record the first and the last node of a group
+ loopsStartEnd.insert(currentGroup.group, sequence.last());
+ currentGroup = postponedGroups.pop();
}
- if (bb->isGroupStart()) {
- currentGroup = bb->containingGroup();
- startEndLoops.insert(bb, sequence.last());
- QList<BasicBlock *> p = postponed;
- foreach (BasicBlock *pBB, p)
- DFS(pBB);
+ BasicBlock *next = currentGroup.postponed.pop();
+ if (checkCandidate(next))
+ return next;
+ }
+
+ return 0;
+ }
+
+ void emitBlock(BasicBlock *bb)
+ {
+ if (emitted.alreadyProcessed(bb))
+ return;
+
+ sequence.append(bb);
+ emitted.markAsProcessed(bb);
+ }
+
+ void schedule(BasicBlock *functionEntryPoint)
+ {
+ BasicBlock *next = functionEntryPoint;
+
+ while (next) {
+ emitBlock(next);
+ for (int i = next->out.size(); i != 0; ) {
+ // postpone all outgoing edges, if they were not already processed
+ --i;
+ BasicBlock *out = next->out[i];
+ if (!emitted.alreadyProcessed(out))
+ postpone(out);
}
+ next = pickNext();
}
+ }
- void layout(BasicBlock *bb) {
- sequence.append(bb);
- visited.insert(bb);
- postponed.removeAll(bb);
+ void postpone(BasicBlock *bb)
+ {
+ if (currentGroup.group == bb->containingGroup()) {
+ currentGroup.postponed.append(bb);
+ return;
}
- };
- QVector<BasicBlock *> sequence;
- sequence.reserve(function->basicBlocks.size());
- QHash<BasicBlock *, BasicBlock *> startEndLoops;
- I(df, sequence, startEndLoops).DFS(function->basicBlocks.first());
- qSwap(function->basicBlocks, sequence);
+ for (int i = postponedGroups.size(); i != 0; ) {
+ --i;
+ WorkForGroup &g = postponedGroups[i];
+ if (g.group == bb->containingGroup()) {
+ g.postponed.append(bb);
+ return;
+ }
+ }
- return startEndLoops;
-}
+ Q_UNREACHABLE();
+ }
+
+public:
+ BlockScheduler(Function *function, const DominatorTree &dominatorTree)
+ : function(function)
+ , dominatorTree(dominatorTree)
+ , emitted(function->basicBlocks)
+ {}
+
+ QHash<BasicBlock *, BasicBlock *> go()
+ {
+ showMeTheCode(function);
+ schedule(function->basicBlocks.first());
+
+ Q_ASSERT(function->basicBlocks.size() == sequence.size());
+ function->basicBlocks = sequence;
+ return loopsStartEnd;
+ }
+};
#ifndef QT_NO_DEBUG
void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
@@ -2277,22 +2679,6 @@ private:
}
};
-inline Temp *unescapableTemp(Expr *e, bool variablesCanEscape)
-{
- Temp *t = e->asTemp();
- if (!t)
- return 0;
-
- switch (t->kind) {
- case Temp::VirtualRegister:
- return t;
- case Temp::Local:
- return variablesCanEscape ? 0 : t;
- default:
- return 0;
- }
-}
-
namespace {
/// This function removes the basic-block from the function's list, unlinks any uses and/or defs,
/// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them
@@ -2513,15 +2899,16 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
continue;
}
if (Member *member = m->source->asMember()) {
- if (member->memberIsEnum) {
+ if (member->kind == Member::MemberOfEnum) {
Const *c = function->New<Const>();
- c->init(SInt32Type, member->enumValue);
+ const int enumValue = member->attachedPropertiesIdOrEnumValue;
+ c->init(SInt32Type, enumValue);
W += replaceUses(targetTemp, c);
defUses.removeDef(*targetTemp);
*ref[s] = 0;
defUses.removeUse(s, *member->base->asTemp());
continue;
- } else if (member->attachedPropertiesId != 0 && member->property && member->base->asTemp()) {
+ } else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) {
// Attached properties have no dependency on their base. Isel doesn't
// need it and we can eliminate the temp used to initialize it.
defUses.removeUse(s, *member->base->asTemp());
@@ -2570,7 +2957,7 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
doneSomething = true;
break;
case OpUPlus:
- constOperand->type = DoubleType;
+ constOperand->type = unop->type;
doneSomething = true;
break;
case OpCompl:
@@ -2603,13 +2990,40 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
if (Binop *binop = m->source->asBinop()) {
+ Const *leftConst = binop->left->asConst();
+ Const *rightConst = binop->right->asConst();
+
+ { // Typical casts to int32:
+ Expr *casted = 0;
+ switch (binop->op) {
+ case OpBitAnd:
+ if (leftConst && !rightConst && leftConst->value == 0xffffffff)
+ casted = rightConst;
+ else if (!leftConst && rightConst && rightConst->value == 0xffffffff)
+ casted = leftConst;
+ break;
+ case OpBitOr:
+ if (leftConst && !rightConst && leftConst->value == 0)
+ casted = rightConst;
+ else if (!leftConst && rightConst && rightConst->value == 0)
+ casted = leftConst;
+ break;
+ default:
+ break;
+ }
+ if (casted) {
+ Q_ASSERT(casted->type == SInt32Type);
+ m->source = casted;
+ W += m;
+ continue;
+ }
+ }
+
// TODO: More constant binary expression evaluation
// TODO: If the result of the move is only used in one single cjump, then
// inline the binop into the cjump.
- Const *leftConst = binop->left->asConst();
if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType)
continue;
- Const *rightConst = binop->right->asConst();
if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType)
continue;
@@ -3013,10 +3427,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// showMeTheCode(function);
static bool doSSA = qgetenv("QV4_NO_SSA").isEmpty();
- static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) {
-// qout << "SSA for " << *function->name << endl;
+// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
// qout << "Starting edge splitting..." << endl;
splitCriticalEdges(function);
// showMeTheCode(function);
@@ -3039,10 +3452,15 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
TypeInference(qmlEngine, defUses).run(function);
// showMeTheCode(function);
+// qout << "Doing reverse inference..." << endl;
+ ReverseInference(defUses).run(function);
+// showMeTheCode(function);
+
// qout << "Doing type propagation..." << endl;
TypePropagation(defUses).run(function);
// showMeTheCode(function);
+ static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
if (doOpt) {
// qout << "Running SSA optimization..." << endl;
optimizeSSA(function, defUses);
@@ -3058,11 +3476,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// block scheduling, so remove those now.
// qout << "Cleaning up unreachable basic blocks..." << endl;
cleanupBasicBlocks(function, false);
-// showMeTheCode(function);
+ showMeTheCode(function);
// qout << "Doing block scheduling..." << endl;
- startEndLoops = scheduleBlocks(function, df);
-// showMeTheCode(function);
+ startEndLoops = BlockScheduler(function, df).go();
+ showMeTheCode(function);
#ifndef QT_NO_DEBUG
checkCriticalEdges(function->basicBlocks);
@@ -3328,3 +3746,7 @@ MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QLis
output.append(m);
return NormalMove;
}
+
+// References:
+// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
+// CGO’10, ACM Press, 2010
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index c2e9eb421a..5959a526bb 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -381,9 +381,9 @@ struct QQmlPixmapProfiler {
QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapReferenceCountChanged, pixmapUrl, referenceCount);
}
}
- void setSize(const QUrl &pixmapUrl, int width, int height) {
- if (enabled) {
- QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapSizeKnown, pixmapUrl, width, height);
+ void setSize(const QUrl &pixmapUrl, const QSize &size) {
+ if (enabled && size.width() > 0) {
+ QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapSizeKnown, pixmapUrl, size.width(), size.height());
}
}
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index 400bb18edd..372a51e997 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -432,7 +432,7 @@ public:
QJsonArray scopes;
// Only type and index are used by Qt Creator, so we keep it easy:
- QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ QVector<QV4::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
int type = encodeScopeType(scopeTypes[i]);
if (type == -1)
@@ -448,7 +448,7 @@ public:
return frame;
}
- int encodeScopeType(QV4::ExecutionContext::Type scopeType)
+ int encodeScopeType(QV4::ExecutionContext::ContextType scopeType)
{
switch (scopeType) {
case QV4::ExecutionContext::Type_GlobalContext:
@@ -480,7 +480,7 @@ public:
QJsonObject anonymous;
anonymous[QLatin1String("properties")] = properties;
- QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ QVector<QV4::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
scope[QLatin1String("index")] = scopeNr;
scope[QLatin1String("frameIndex")] = frameNr;
@@ -619,7 +619,7 @@ public:
addRunning();
QJsonObject body;
body.insert(QStringLiteral("V8Version"),
- QStringLiteral("this is not V8, this is V4 in Qt %1").arg(QLatin1String(QT_VERSION_STR)));
+ QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
addBody(body);
}
};
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 1b11fa1bf7..74aaae7724 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -48,6 +48,10 @@ exampledirs += ../../../examples/qml \
imagedirs += images
+# Add a thumbnail for examples that do not have images
+manifestmeta.thumbnail.names += "QtQml/Chapter 4*" \
+ "QtQml/Chapter 6*"
+
navigation.landingpage = "Qt QML"
navigation.cppclassespage = "Qt QML C++ Classes"
navigation.qmltypespage = "Qt QML QML Types"
diff --git a/src/qml/doc/snippets/package/Delegate.qml b/src/qml/doc/snippets/package/Delegate.qml
new file mode 100644
index 0000000000..641de67a62
--- /dev/null
+++ b/src/qml/doc/snippets/package/Delegate.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//! [0]
+Package {
+ Text { id: listDelegate; width: parent.width; height: 25; text: 'Empty'; Package.name: 'list' }
+ Text { id: gridDelegate; width: parent.width / 2; height: 50; text: 'Empty'; Package.name: 'grid' }
+
+ Rectangle {
+ id: wrapper
+ width: parent.width; height: 25
+ color: 'lightsteelblue'
+
+ Text { text: display; anchors.centerIn: parent }
+ state: root.upTo > index ? 'inGrid' : 'inList'
+ states: [
+ State {
+ name: 'inList'
+ ParentChange { target: wrapper; parent: listDelegate }
+ },
+ State {
+ name: 'inGrid'
+ ParentChange {
+ target: wrapper; parent: gridDelegate
+ x: 0; y: 0; width: gridDelegate.width; height: gridDelegate.height
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ ParentAnimation {
+ NumberAnimation { properties: 'x,y,width,height'; duration: 300 }
+ }
+ }
+ ]
+ }
+}
+//! [0]
diff --git a/src/qml/doc/snippets/package/view.qml b/src/qml/doc/snippets/package/view.qml
new file mode 100644
index 0000000000..820eb4068c
--- /dev/null
+++ b/src/qml/doc/snippets/package/view.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQml.Models 2.1
+
+Rectangle {
+ id: root
+ color: "white"
+ width: 320
+ height: 480
+ property int upTo: 0
+ SequentialAnimation on upTo {
+ loops: -1
+ NumberAnimation { to: 8; duration: 3500 }
+ NumberAnimation { to: 0; duration: 3500 }
+ }
+
+ ListModel {
+ id: myModel
+ ListElement { display: "One" }
+ ListElement { display: "Two" }
+ ListElement { display: "Three" }
+ ListElement { display: "Four" }
+ ListElement { display: "Five" }
+ ListElement { display: "Six" }
+ ListElement { display: "Seven" }
+ ListElement { display: "Eight" }
+ }
+ //![0]
+ DelegateModel {
+ id: visualModel
+ delegate: Delegate {}
+ model: myModel
+ }
+
+ ListView {
+ id: lv
+ height: parent.height/2
+ width: parent.width
+
+ model: visualModel.parts.list
+ }
+ GridView {
+ y: parent.height/2
+ height: parent.height/2
+ width: parent.width
+ cellWidth: width / 2
+ cellHeight: 50
+ model: visualModel.parts.grid
+ }
+ //![0]
+ Text {
+ anchors.bottom: parent.bottom
+ }
+}
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index d0fb03a03c..ecfcf8f106 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -397,36 +397,50 @@ The complete code can be seen in the updated \c examples/qml/tutorials/extending
Currently the \c PieChart and \c PieSlice types are used by \c app.qml,
which is displayed using a QQuickView in a C++ application. An alternative
way to use our QML extension is to create a plugin library to make it available
-to the QML engine. This would allow the \c PieChart and \c PieSlice types to be
-registered into a type namespace which could be imported by any QML application,
-instead of restricting these types to be only used by the one application.
+to the QML engine as a new QML import module. This allows the \c PieChart and
+\c PieSlice types to be registered into a type namespace which can be imported
+by any QML application, instead of restricting these types to be only used by
+the one application.
-The setps for creating a plugin are described in \l {Creating C++ Plugins for QML}.
+The steps for creating a plugin are described in \l {Creating C++ Plugins for QML}.
To start with, we create a plugin class named \c ChartsPlugin. It subclasses QQmlExtensionPlugin
and registers our QML types in the inherited \l{QQmlExtensionPlugin::}{registerTypes()} method.
Here is the \c ChartsPlugin definition in \c chartsplugin.h:
-\snippet tutorials/extending/chapter6-plugins/chartsplugin.h 0
+\snippet tutorials/extending/chapter6-plugins/import/chartsplugin.h 0
And its implementation in \c chartsplugin.cpp:
-\snippet tutorials/extending/chapter6-plugins/chartsplugin.cpp 0
+\snippet tutorials/extending/chapter6-plugins/import/chartsplugin.cpp 0
Then, we write a \c .pro project file that defines the project as a plugin library
-and specifies with DESTDIR that library files should be built into a "lib" subdirectory:
+and specifies with DESTDIR that library files should be built into a \c {../Charts}
+directory.
-\quotefile tutorials/extending/chapter6-plugins/chapter6-plugins.pro
+\quotefile tutorials/extending/chapter6-plugins/import/import.pro
-Finally, we add a \l{qtqml-modules-qmldir.html}{qmldir} file that is
-parsed by the QML engine. In this file, we specify that a plugin named
-"chapter6-plugin" (the name of the example project) can be found in the "lib" subdirectory:
+In this example, the \c Charts directory is located at the same level as the application
+that uses our new import module. This way, the QML engine will find our module
+as the default search path for QML imports includes the directory of the application
+executable. Alternatively, we could control what directories the \l {QML Import Path}
+{QML import path} contains, useful if there are multiple QML applications using the
+same QML imports.
-\quotefile tutorials/extending/chapter6-plugins/Charts/qmldir
+The \c .pro file also contains additional magic to ensure that the
+\l {Module Definition qmldir Files}{module definition qmldir file} is always copied
+to the same location as the plugin binary.
-Now we have a plugin, and instead of having a main.cpp and an executable, we can build
-the project and then load the QML file using the \l{Prototyping with qmlscene}{qmlscene tool},
-setting the import path to the current directory so that it finds the \c qmldir file:
+The \c qmldir file declares the module name and the plugin that is made available
+by the module:
+
+\quotefile tutorials/extending/chapter6-plugins/import/qmldir
+
+Now we have a QML module that can be imported to any application, provided that the
+QML engine knows where to find it. The example contains an executable that loads
+\c app.qml, which uses the \c {import Charts 1.0} statement. Alternatively, you can
+load the QML file using the \l{Prototyping with qmlscene}{qmlscene tool}, setting the
+import path to the current directory so that it finds the \c qmldir file:
\code
qmlscene -I . app.qml
@@ -434,7 +448,6 @@ setting the import path to the current directory so that it finds the \c qmldir
The module "Charts" will be loaded by the QML engine, and the types provided by that
module will be available for use in any QML document which imports it.
-
*/
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 5d8a0202fa..a19c358231 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -49,6 +49,7 @@
#include "private/qv4mm_p.h"
#include "private/qv4globalobject_p.h"
#include "private/qv4script_p.h"
+#include "private/qv4runtime_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qmetaobject.h>
@@ -260,7 +261,7 @@ void QJSEngine::collectGarbage()
QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
{
QV4::Scope scope(d->m_v4Engine);
- QV4::ExecutionContext *ctx = d->m_v4Engine->current;
+ QV4::ExecutionContext *ctx = d->m_v4Engine->currentContext();
QV4::ScopedValue result(scope);
QV4::Script script(ctx, program, fileName, lineNumber);
@@ -376,6 +377,54 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
QV4::Scope scope(engine->m_v4Engine);
QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine));
return engine->metaTypeFromJS(v, type, ptr);
+ } else if (vp->value.isEmpty()) {
+ // have a string based value without engine. Do conversion manually
+ if (type == QMetaType::Bool) {
+ *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0;
+ return true;
+ }
+ if (type == QMetaType::QString) {
+ *reinterpret_cast<QString*>(ptr) = vp->string;
+ return true;
+ }
+ double d = QV4::__qmljs_string_to_number(vp->string);
+ switch (type) {
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = QV4::Primitive::toInteger(d);
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = QV4::Primitive::toInteger(d);
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = d;
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = d;
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ default:
+ return false;
+ }
} else {
switch (type) {
case QMetaType::Bool:
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 4035fb9fa6..d7a1cef3ba 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -58,20 +58,22 @@
QV4::ReturnedValue QJSValuePrivate::getValue(QV4::ExecutionEngine *e)
{
- if (!this->engine)
+ if (!this->engine) {
this->engine = e;
- else if (this->engine != e) {
+ } else if (this->engine != e) {
qWarning("JSValue can't be reassigned to another engine.");
return QV4::Encode::undefined();
}
- if (value.asString() == &string) {
- value = QV4::Encode(engine->newString(string.toQString()));
+
+ if (value.isEmpty()) {
+ value = QV4::Encode(engine->newString(string));
PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues;
prev = listRoot;
next = *listRoot;
*prev = this;
if (next)
next->prev = &this->next;
+ string = QString();
}
return value.asReturnedValue();
}
@@ -210,7 +212,7 @@ QJSValue::QJSValue(const QLatin1String &value)
*/
#ifndef QT_NO_CAST_FROM_ASCII
QJSValue::QJSValue(const char *value)
- : d(new QJSValuePrivate(QString::fromLatin1(value)))
+ : d(new QJSValuePrivate(QString::fromUtf8(value)))
{
}
#endif
@@ -275,7 +277,7 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- return d->value.isString();
+ return d->value.isEmpty() || d->value.isString();
}
/*!
@@ -359,6 +361,8 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
+ if (d->value.isEmpty())
+ return d->string;
return d->value.toQStringNoThrow();
}
@@ -376,7 +380,10 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return __qmljs_string_to_number(d->string);
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
double dbl = d->value.toNumber();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -399,7 +406,10 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return d->string.length() > 0;
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
bool b = d->value.toBoolean();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -422,7 +432,10 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return QV4::Primitive::toInt32(__qmljs_string_to_number(d->string));
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
qint32 i = d->value.toInt32();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -445,7 +458,10 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return QV4::Primitive::toUInt32(__qmljs_string_to_number(d->string));
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
quint32 u = d->value.toUInt32();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -478,6 +494,9 @@ quint32 QJSValue::toUInt() const
*/
QVariant QJSValue::toVariant() const
{
+ if (d->value.isEmpty())
+ return QVariant(d->string);
+
return QV4::VariantObject::toVariant(d->value);
}
@@ -517,7 +536,7 @@ QJSValue QJSValue::call(const QJSValueList &args)
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->call(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -571,7 +590,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->call(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -617,7 +636,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->construct(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -720,6 +739,22 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
return *this;
}
+static bool js_equal(const QString &string, QV4::ValueRef value)
+{
+ if (value->isString())
+ return string == value->stringValue()->toQString();
+ if (value->isNumber())
+ return __qmljs_string_to_number(string) == value->asDouble();
+ if (value->isBoolean())
+ return __qmljs_string_to_number(string) == value->booleanValue();
+ if (value->isObject()) {
+ Scope scope(value->objectValue()->engine());
+ ScopedValue p(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT));
+ return js_equal(string, p);
+ }
+ return false;
+}
+
/*!
Returns true if this QJSValue is equal to \a other, otherwise
returns false. The comparison follows the behavior described in
@@ -746,6 +781,14 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
*/
bool QJSValue::equals(const QJSValue& other) const
{
+ if (d->value.isEmpty()) {
+ if (other.d->value.isEmpty())
+ return d->string == other.d->string;
+ return js_equal(d->string, QV4::ValueRef(other.d->value));
+ }
+ if (other.d->value.isEmpty())
+ return other.equals(*this);
+
return __qmljs_cmp_eq(QV4::ValueRef(d), QV4::ValueRef(other.d));
}
@@ -773,6 +816,16 @@ bool QJSValue::equals(const QJSValue& other) const
*/
bool QJSValue::strictlyEquals(const QJSValue& other) const
{
+ if (d->value.isEmpty()) {
+ if (other.d->value.isEmpty())
+ return d->string == other.d->string;
+ if (other.d->value.isString())
+ return d->string == other.d->value.stringValue()->toQString();
+ return false;
+ }
+ if (other.d->value.isEmpty())
+ return other.strictlyEquals(*this);
+
return __qmljs_strict_equal(QV4::ValueRef(d), QV4::ValueRef(other.d));
}
@@ -806,7 +859,7 @@ QJSValue QJSValue::property(const QString& name) const
return property(idx);
s->makeIdentifier();
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
result = o->get(s);
if (scope.hasException())
@@ -838,7 +891,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
if (!o)
return QJSValue();
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
if (scope.hasException())
@@ -880,7 +933,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
return;
}
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
s->makeIdentifier();
QV4::ScopedValue v(scope, value.d->getValue(engine));
o->put(s, v);
@@ -911,7 +964,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
if (!o)
return;
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue v(scope, value.d->getValue(engine));
if (arrayIndex != UINT_MAX)
o->putIndexed(arrayIndex, v);
@@ -944,7 +997,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
bool QJSValue::deleteProperty(const QString &name)
{
ExecutionEngine *engine = d->engine;
- ExecutionContext *ctx = engine->current;
+ ExecutionContext *ctx = engine->currentContext();
Scope scope(engine);
ScopedObject o(scope, d->value.asObject());
if (!o)
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index bf839a6f1f..d8da664cc6 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -80,17 +80,16 @@ public:
Q_ASSERT(!value.isEmpty());
}
QJSValuePrivate(const QString &s)
- : PersistentValuePrivate(QV4::Encode::undefined())
- , string(0, s)
+ : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue())
+ , string(s)
{
- value.val = QV4::Encode(string.asReturned<QV4::String>());
}
QV4::ReturnedValue getValue(QV4::ExecutionEngine *e);
static QJSValuePrivate *get(const QJSValue &v) { return v.d; }
- QV4::String string;
+ QString string;
};
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 245b75b384..ed011ef691 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -59,7 +59,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
QV4::Scope scope(e);
QV4::ScopedObject o(scope, jsp->value);
- iterator = e->newForEachIteratorObject(e->current, o)->asReturnedValue();
+ iterator = e->newForEachIteratorObject(e->currentContext(), o)->asReturnedValue();
currentName = (QV4::String *)0;
nextName = (QV4::String *)0;
@@ -198,7 +198,7 @@ QJSValue QJSValueIterator::value() const
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
QV4::ScopedObject o(scope, it->it.object);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue v(scope);
if (!!d_ptr->currentName) {
QV4::ScopedString n(scope, d_ptr->currentName);
@@ -237,7 +237,7 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
QJSValuePrivate *jsp = QJSValuePrivate::get(object);
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, jsp->value);
- d_ptr->iterator = v4->newForEachIteratorObject(v4->current, o)->asReturnedValue();
+ d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue();
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
it->it.flags = QV4::ObjectIterator::NoFlags;
it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 749509c353..629c255b48 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -47,9 +47,10 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(ArgumentsObject);
ArgumentsObject::ArgumentsObject(CallContext *context)
- : Object(context->engine), context(context), fullyCreated(false)
+ : Object(context->strictMode ? context->engine->strictArgumentsObjectClass : context->engine->argumentsObjectClass)
+ , context(context)
+ , fullyCreated(false)
{
- vtbl = &static_vtbl;
type = Type_ArgumentsObject;
flags &= ~SimpleArray;
@@ -58,8 +59,6 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
ScopedObject protectThis(scope, this);
if (context->strictMode) {
- internalClass = v4->strictArgumentsObjectClass;
-
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
@@ -72,7 +71,6 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
arrayDataLen = context->callData->argc;
fullyCreated = true;
} else {
- internalClass = engine()->argumentsObjectClass;
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
memberData[CalleePropertyIndex].value = context->function->asReturnedValue();
isNonStrictArgumentsObject = true;
@@ -80,6 +78,8 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
lp->value = Primitive::fromInt32(context->realArgumentCount);
+
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
}
void ArgumentsObject::destroy(Managed *that)
@@ -215,7 +215,7 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc));
return o->context->argument(g->index);
@@ -230,7 +230,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
Q_ASSERT(s->index < static_cast<unsigned>(o->context->callData->argc));
o->context->callData->args[s->index] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 7c58c48bcc..d306fae92b 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -54,7 +54,9 @@ struct ArgumentsGetterFunction: FunctionObject
uint index;
ArgumentsGetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+ : FunctionObject(scope), index(index) {
+ setVTable(&static_vtbl);
+ }
static ReturnedValue call(Managed *that, CallData *d);
};
@@ -65,7 +67,9 @@ struct ArgumentsSetterFunction: FunctionObject
uint index;
ArgumentsSetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+ : FunctionObject(scope), index(index) {
+ setVTable(&static_vtbl);
+ }
static ReturnedValue call(Managed *that, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a0f0345b8b..1628cfe4da 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -51,7 +51,7 @@ DEFINE_MANAGED_VTABLE(ArrayCtor);
ArrayCtor::ArrayCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Array"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
@@ -65,7 +65,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
len = callData->args[0].asArrayLength(&ok);
if (!ok)
- return v4->current->throwRangeError(callData->args[0]);
+ return v4->currentContext()->throwRangeError(callData->args[0]);
if (len < 0x1000)
a->arrayReserve(len);
@@ -174,12 +174,22 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
}
ScopedArrayObject elt(scope);
+ ScopedObject eltAsObj(scope);
+ ScopedValue entry(scope);
for (int i = 0; i < ctx->callData->argc; ++i) {
+ eltAsObj = ctx->callData->args[i];
elt = ctx->callData->args[i];
- if (elt)
+ if (elt) {
result->arrayConcat(elt.getPointer());
- else
+ } else if (eltAsObj && eltAsObj->isListType()) {
+ const uint startIndex = getLength(ctx, result);
+ for (int i = 0, len = getLength(ctx, eltAsObj); i < len; ++i) {
+ entry = eltAsObj->getIndexed(i);
+ result->putIndexed(startIndex + i, entry);
+ }
+ } else {
result->arraySet(getLength(ctx, result), ctx->callData->args[i]);
+ }
}
return result.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index a0d0027e5f..f8edfb7850 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -49,7 +49,7 @@ DEFINE_MANAGED_VTABLE(BooleanObject);
BooleanCtor::BooleanCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Boolean"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 56c00f99ed..8d6adc0fb2 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -39,7 +39,7 @@
**
****************************************************************************/
#ifndef QV4BOOLEANOBJECT_H
-#define QBOOLEANOBJECT_H
+#define QV4BOOLEANOBJECT_H
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 372c9ce54b..05a0e66e09 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -58,7 +58,6 @@ const ManagedVTable ExecutionContext::static_vtbl =
markObjects,
destroy,
0 /*collectDeletables*/,
- hasInstance,
0,
0,
0,
@@ -77,11 +76,7 @@ const ManagedVTable ExecutionContext::static_vtbl =
CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
{
CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
- c->init();
-
- engine->current = c;
-
- c->initBaseContext(Type_CallContext, engine, this);
+ new (c) CallContext(engine, Type_CallContext);
c->function = function;
c->realArgumentCount = callData->argc;
@@ -115,28 +110,20 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
WithContext *ExecutionContext::newWithContext(ObjectRef with)
{
- WithContext *w = new (engine->memoryManager) WithContext;
- engine->current = w;
- w->initWithContext(this, with);
+ WithContext *w = new (engine->memoryManager) WithContext(engine, with);
return w;
}
CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue)
{
- CatchContext *c = new (engine->memoryManager) CatchContext;
- engine->current = c;
- c->initCatchContext(this, exceptionVarName, exceptionValue);
+ CatchContext *c = new (engine->memoryManager) CatchContext(engine, exceptionVarName, exceptionValue);
return c;
}
CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml)
{
CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
- c->init();
-
- engine->current = c;
- c->initQmlContext(this, qml, f);
-
+ new (c) CallContext(engine, qml, f);
return c;
}
@@ -173,7 +160,7 @@ String * const *ExecutionContext::formals() const
if (type < Type_SimpleCallContext)
return 0;
QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
- return f ? f->formalParameterList : 0;
+ return (f && f->function) ? f->function->internalClass->nameMap.constData() : 0;
}
unsigned int ExecutionContext::formalCount() const
@@ -189,7 +176,7 @@ String * const *ExecutionContext::variables() const
if (type < Type_SimpleCallContext)
return 0;
QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
- return f ? f->varList : 0;
+ return (f && f->function) ? f->function->internalClass->nameMap.constData() + f->function->nArguments : 0;
}
unsigned int ExecutionContext::variableCount() const
@@ -201,53 +188,47 @@ unsigned int ExecutionContext::variableCount() const
}
-void GlobalContext::initGlobalContext(ExecutionEngine *eng)
+GlobalContext::GlobalContext(ExecutionEngine *eng)
+ : ExecutionContext(eng, Type_GlobalContext)
{
- initBaseContext(Type_GlobalContext, eng, /*parentContext*/0);
- callData = reinterpret_cast<CallData *>(this + 1);
- callData->tag = QV4::Value::_Integer_Type;
- callData->argc = 0;
- callData->thisObject = eng->globalObject;
- callData->args[0] = Encode::undefined();
- global = 0;
+ global = eng->globalObject;
}
-void WithContext::initWithContext(ExecutionContext *p, ObjectRef with)
+WithContext::WithContext(ExecutionEngine *engine, ObjectRef with)
+ : ExecutionContext(engine, Type_WithContext)
{
- initBaseContext(Type_WithContext, p->engine, p);
- callData = p->callData;
- outer = p;
- lookups = p->lookups;
- compilationUnit = p->compilationUnit;
+ callData = parent->callData;
+ outer = parent;
+ lookups = parent->lookups;
+ compilationUnit = parent->compilationUnit;
withObject = with.getPointer();
}
-void CatchContext::initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue)
+CatchContext::CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue)
+ : ExecutionContext(engine, Type_CatchContext)
{
- initBaseContext(Type_CatchContext, p->engine, p);
- strictMode = p->strictMode;
- callData = p->callData;
- outer = p;
- lookups = p->lookups;
- compilationUnit = p->compilationUnit;
+ strictMode = parent->strictMode;
+ callData = parent->callData;
+ outer = parent;
+ lookups = parent->lookups;
+ compilationUnit = parent->compilationUnit;
this->exceptionVarName = exceptionVarName;
this->exceptionValue = exceptionValue;
}
-void CallContext::initQmlContext(ExecutionContext *parentContext, ObjectRef qml, FunctionObject *function)
+CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject *function)
+ : ExecutionContext(engine, Type_QmlContext)
{
- initBaseContext(Type_QmlContext, parentContext->engine, parentContext);
-
this->function = function;
- this->callData = reinterpret_cast<CallData *>(this + 1);
- this->callData->tag = QV4::Value::_Integer_Type;
- this->callData->argc = 0;
- this->callData->thisObject = Primitive::undefinedValue();
+ callData = reinterpret_cast<CallData *>(this + 1);
+ callData->tag = QV4::Value::_Integer_Type;
+ callData->argc = 0;
+ callData->thisObject = Primitive::undefinedValue();
strictMode = true;
- this->outer = function->scope;
+ outer = function->scope;
#ifndef QT_NO_DEBUG
assert(outer->next != (ExecutionContext *)0x1);
#endif
@@ -283,12 +264,10 @@ bool ExecutionContext::deleteProperty(const StringRef name)
CallContext *c = static_cast<CallContext *>(ctx);
FunctionObject *f = c->function;
if (f->needsActivation || hasWith) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return false;
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return false;
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX)
+ // ### throw in strict mode?
+ return false;
}
if (c->activation && c->activation->__hasProperty__(name))
return c->activation->deleteProperty(name);
@@ -358,24 +337,35 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
ScopedObject activation(scope, (Object *)0);
if (ctx->type >= Type_CallContext) {
CallContext *c = static_cast<CallContext *>(ctx);
- for (unsigned int i = 0; i < c->function->varCount; ++i)
- if (c->function->varList[i]->isEqualTo(name)) {
- c->locals[i] = *value;
- return;
- }
- for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i)
- if (c->function->formalParameterList[i]->isEqualTo(name)) {
- c->callData->args[i] = *value;
+ if (c->function->function) {
+ uint index = c->function->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount) {
+ c->callData->args[c->function->formalParameterCount - index - 1] = *value;
+ } else {
+ index -= c->function->formalParameterCount;
+ c->locals[index] = *value;
+ }
return;
}
+ }
activation = c->activation;
} else if (ctx->type == Type_GlobalContext) {
activation = static_cast<GlobalContext *>(ctx)->global;
}
- if (activation && (ctx->type == Type_QmlContext || activation->__hasProperty__(name))) {
- activation->put(name, value);
- return;
+ if (activation) {
+ if (ctx->type == Type_QmlContext) {
+ activation->put(name, value);
+ return;
+ } else {
+ PropertyAttributes attrs;
+ Property *p = activation->__getOwnProperty__(name, &attrs);
+ if (p) {
+ activation->putValue(p, attrs, value);
+ return;
+ }
+ }
}
}
}
@@ -420,13 +410,13 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name)
else if (ctx->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
ScopedFunctionObject f(scope, c->function);
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
+ if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount)
+ return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue();
+ return c->locals[index - c->function->formalParameterCount].asReturnedValue();
+ }
}
if (c->activation) {
bool hasProperty = false;
@@ -486,13 +476,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR
else if (ctx->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
FunctionObject *f = c->function;
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
+ if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount)
+ return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue();
+ return c->locals[index - c->function->formalParameterCount].asReturnedValue();
+ }
}
if (c->activation) {
bool hasProperty = false;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index e7f5ee9a9e..4eb89ad905 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -44,6 +44,7 @@
#include "qv4global_p.h"
#include "qv4value_def_p.h"
#include "qv4managed_p.h"
+#include "qv4engine_p.h"
QT_BEGIN_NAMESPACE
@@ -69,19 +70,8 @@ struct WithContext;
struct Q_QML_EXPORT ExecutionContext : public Managed
{
Q_MANAGED
- ExecutionContext()
- : Managed(0) {
- vtbl = &static_vtbl;
- }
- void init() {
- _data = 0;
- internalClass = 0;
- inUse = 1;
- extensible = 1;
- vtbl = &static_vtbl;
- }
- enum Type {
+ enum ContextType {
Type_GlobalContext = 0x1,
Type_CatchContext = 0x2,
Type_WithContext = 0x3,
@@ -90,7 +80,23 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
Type_QmlContext = 0x6
};
- Type type;
+ ExecutionContext(ExecutionEngine *engine, ContextType t)
+ : Managed(engine->executionContextClass)
+ {
+ this->type = t;
+ strictMode = false;
+ this->engine = engine;
+ this->parent = engine->currentContext();
+ outer = 0;
+ lookups = 0;
+ compilationUnit = 0;
+ currentEvalCode = 0;
+ interpreterInstructionPointer = 0;
+ lineNumber = -1;
+ engine->current = this;
+ }
+
+ ContextType type;
bool strictMode;
CallData *callData;
@@ -112,25 +118,12 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
const uchar **interpreterInstructionPointer;
int lineNumber;
- void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
- {
- this->type = type;
- strictMode = false;
- this->engine = engine;
- parent = parentContext;
- outer = 0;
- lookups = 0;
- compilationUnit = 0;
- currentEvalCode = 0;
- interpreterInstructionPointer = 0;
- lineNumber = -1;
- }
-
CallContext *newCallContext(FunctionObject *f, CallData *callData);
WithContext *newWithContext(ObjectRef with);
CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue);
CallContext *newQmlContext(FunctionObject *f, ObjectRef qml);
+ // formals are in reverse order
String * const *formals() const;
unsigned int formalCount() const;
String * const *variables() const;
@@ -167,18 +160,19 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
struct CallContext : public ExecutionContext
{
- FunctionObject *function;
- int realArgumentCount;
- SafeValue *locals;
- Object *activation;
-
- void initSimpleCallContext(ExecutionEngine *engine, ExecutionContext *parent) {
- initBaseContext(Type_SimpleCallContext, engine, parent);
+ CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
+ : ExecutionContext(engine, t)
+ {
function = 0;
locals = 0;
activation = 0;
}
- void initQmlContext(ExecutionContext *parentContext, ObjectRef qml, QV4::FunctionObject *function);
+ CallContext(ExecutionEngine *engine, ObjectRef qml, QV4::FunctionObject *function);
+
+ FunctionObject *function;
+ int realArgumentCount;
+ SafeValue *locals;
+ Object *activation;
inline ReturnedValue argument(int i);
bool needsOwnArguments() const;
@@ -186,14 +180,14 @@ struct CallContext : public ExecutionContext
struct GlobalContext : public ExecutionContext
{
- void initGlobalContext(ExecutionEngine *e);
+ GlobalContext(ExecutionEngine *engine);
Object *global;
};
struct CatchContext : public ExecutionContext
{
- void initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue);
+ CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue);
SafeString exceptionVarName;
SafeValue exceptionValue;
@@ -201,9 +195,8 @@ struct CatchContext : public ExecutionContext
struct WithContext : public ExecutionContext
{
+ WithContext(ExecutionEngine *engine, ObjectRef with);
Object *withObject;
-
- void initWithContext(ExecutionContext *p, ObjectRef with);
};
inline CallContext *ExecutionContext::asCallContext()
@@ -216,6 +209,37 @@ inline const CallContext *ExecutionContext::asCallContext() const
return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
}
+
+inline void ExecutionEngine::pushContext(CallContext *context)
+{
+ context->parent = current;
+ current = context;
+ current->currentEvalCode = 0;
+}
+
+inline ExecutionContext *ExecutionEngine::popContext()
+{
+ Q_ASSERT(current->parent);
+ current = current->parent;
+ return current;
+}
+
+struct ExecutionContextSaver
+{
+ ExecutionEngine *engine;
+ ExecutionContext *savedContext;
+
+ ExecutionContextSaver(ExecutionContext *context)
+ : engine(context->engine)
+ , savedContext(context)
+ {
+ }
+ ~ExecutionContextSaver()
+ {
+ engine->current = savedContext;
+ }
+};
+
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) + sizeof(CallData)
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b732c8a04a..5d0c8ccf8e 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -646,7 +646,7 @@ DEFINE_MANAGED_VTABLE(DateObject);
DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
: Object(engine->dateClass)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_DateObject;
value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN());
}
@@ -661,7 +661,7 @@ DEFINE_MANAGED_VTABLE(DateCtor);
DateCtor::DateCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Date"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue DateCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index e96cac2f20..9c451dd251 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -55,7 +55,6 @@ struct DateObject: Object {
Q_MANAGED
SafeValue value;
DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) {
- vtbl = &static_vtbl;
type = Type_DateObject;
value = date;
}
@@ -65,7 +64,7 @@ struct DateObject: Object {
protected:
DateObject(InternalClass *ic): Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_DateObject;
value = Primitive::fromDouble(qSNaN());
}
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 95b4100651..4170b6817f 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -185,7 +185,7 @@ void Debugger::resume(Speed speed)
if (speed == StepOver)
setTemporaryBreakPointOnNextLine();
if (speed == StepOut)
- m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->current);
+ m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->currentContext());
m_stepping = speed;
m_runningCondition.wakeAll();
@@ -293,15 +293,16 @@ void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int
if (frameNr < 0)
return;
- CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr);
if (!ctxt)
return;
Scope scope(engine);
ScopedValue v(scope);
- for (unsigned i = 0, ei = ctxt->formalCount(); i != ei; ++i) {
+ int nFormals = ctxt->formalCount();
+ for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
QString qName;
- if (String *name = ctxt->formals()[i])
+ if (String *name = ctxt->formals()[nFormals - i - 1])
qName = name->toQString();
v = ctxt->argument(i);
collector->collect(qName, v);
@@ -339,7 +340,7 @@ void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int sco
if (frameNr < 0)
return;
- CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr);
if (!ctxt)
return;
@@ -386,7 +387,7 @@ bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame)
bool myRun()
{
- ExecutionContext *ctxt = findContext(engine->current, frameNr);
+ ExecutionContext *ctxt = findContext(engine->currentContext(), frameNr);
while (ctxt) {
if (CallContext *cCtxt = ctxt->asCallContext())
if (cCtxt->activation)
@@ -448,14 +449,14 @@ void Debugger::collectReturnedValue(Collector *collector) const
collector->collect(o);
}
-QVector<ExecutionContext::Type> Debugger::getScopeTypes(int frame) const
+QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const
{
- QVector<ExecutionContext::Type> types;
+ QVector<ExecutionContext::ContextType> types;
if (state() != Paused)
return types;
- CallContext *sctxt = findContext(m_engine->current, frame);
+ CallContext *sctxt = findContext(m_engine->currentContext(), frame);
if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext)
return types;
CallContext *ctxt = static_cast<CallContext *>(sctxt);
@@ -499,7 +500,7 @@ void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit)
m_pauseRequested = false;
pauseAndWait(PauseRequest);
} else if (breakPointHit) {
- if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->current)
+ if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->currentContext())
pauseAndWait(Step);
else if (reallyHitTheBreakPoint(state.fileName, state.lineNumber))
pauseAndWait(BreakPoint);
@@ -527,7 +528,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal)
QMutexLocker locker(&m_lock);
if ((m_stepping == StepOut || m_stepping == StepOver)
- && temporaryBreakPointInFunction(m_engine->current)) {
+ && temporaryBreakPointInFunction(m_engine->currentContext())) {
clearTemporaryBreakPoints();
m_stepping = NotStepping;
m_stopForStepping = true;
@@ -551,7 +552,7 @@ void Debugger::aboutToThrow()
Function *Debugger::getFunction() const
{
- ExecutionContext *context = m_engine->current;
+ ExecutionContext *context = m_engine->currentContext();
if (CallContext *callCtx = context->asCallContext())
return callCtx->function->function;
else {
@@ -594,7 +595,7 @@ void Debugger::setTemporaryBreakPointOnNextLine()
if (pcs.isEmpty())
return;
- m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->current);
+ m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->currentContext());
m_temporaryBreakPoints.codeOffsets.reserve(pcs.size());
for (QList<qptrdiff>::const_iterator i = pcs.begin(), ei = pcs.end(); i != ei; ++i) {
// note: we do set a breakpoint on the current line, because there could be a loop where
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 98b549995e..0e19c51935 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -163,7 +163,7 @@ public:
bool collectThisInContext(Collector *collector, int frame = 0);
void collectThrownValue(Collector *collector);
void collectReturnedValue(Collector *collector) const;
- QVector<ExecutionContext::Type> getScopeTypes(int frame = 0) const;
+ QVector<ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
public: // compile-time interface
void maybeBreakAtInstruction(const uchar *code, bool breakPointHit);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index f5a515a0ae..dc8c0da321 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
#include <qv4engine_p.h>
+#include <qv4context_p.h>
#include <qv4value_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
@@ -52,6 +53,7 @@
#include <qv4mathobject_p.h>
#include <qv4numberobject_p.h>
#include <qv4regexpobject_p.h>
+#include <qv4regexp_p.h>
#include <qv4variantobject_p.h>
#include <qv4runtime_p.h>
#include "qv4mm_p.h"
@@ -134,11 +136,13 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
: memoryManager(new QV4::MemoryManager)
, executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
+ , current(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
, debugger(0)
, globalObject(0)
, globalCode(0)
+ , v8Engine(0)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
@@ -181,6 +185,9 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
identifierTable = new IdentifierTable(this);
emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
+ executionContextClass = emptyClass->changeVTable(&ExecutionContext::static_vtbl);
+ stringClass = emptyClass->changeVTable(&String::static_vtbl);
+ regExpValueClass = emptyClass->changeVTable(&RegExp::static_vtbl);
id_undefined = newIdentifier(QStringLiteral("undefined"));
id_null = newIdentifier(QStringLiteral("null"));
@@ -213,33 +220,39 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
id_toString = newIdentifier(QStringLiteral("toString"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
- ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass);
- objectClass = emptyClass->changePrototype(objectPrototype);
+ ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass->changeVTable(&ObjectPrototype::static_vtbl));
+ objectClass = InternalClass::create(this, &Object::static_vtbl, objectPrototype);
+ Q_ASSERT(objectClass->vtable == &Object::static_vtbl);
- arrayClass = objectClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
+ arrayClass = InternalClass::create(this, &ArrayObject::static_vtbl, objectPrototype);
+ arrayClass = arrayClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass);
arrayClass = arrayClass->changePrototype(arrayPrototype);
- InternalClass *argsClass = objectClass->addMember(id_length, Attr_NotEnumerable);
+ InternalClass *argsClass = InternalClass::create(this, &ArgumentsObject::static_vtbl, objectPrototype);
+ argsClass = argsClass->addMember(id_length, Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable);
strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ Q_ASSERT(argumentsObjectClass->vtable == &ArgumentsObject::static_vtbl);
+ Q_ASSERT(strictArgumentsObjectClass->vtable == &ArgumentsObject::static_vtbl);
+
initRootContext();
StringPrototype *stringPrototype = new (memoryManager) StringPrototype(objectClass);
- stringClass = emptyClass->changePrototype(stringPrototype);
+ stringObjectClass = InternalClass::create(this, &String::static_vtbl, stringPrototype);
NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(objectClass);
- numberClass = emptyClass->changePrototype(numberPrototype);
+ numberClass = InternalClass::create(this, &NumberObject::static_vtbl, numberPrototype);
BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(objectClass);
- booleanClass = emptyClass->changePrototype(booleanPrototype);
+ booleanClass = InternalClass::create(this, &BooleanObject::static_vtbl, booleanPrototype);
DatePrototype *datePrototype = new (memoryManager) DatePrototype(objectClass);
- dateClass = emptyClass->changePrototype(datePrototype);
+ dateClass = InternalClass::create(this, &DateObject::static_vtbl, datePrototype);
- FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(objectClass);
- functionClass = emptyClass->changePrototype(functionPrototype);
+ FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, &FunctionPrototype::static_vtbl, objectPrototype));
+ functionClass = InternalClass::create(this, &FunctionObject::static_vtbl, functionPrototype);
uint index;
functionWithProtoClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == FunctionObject::Index_Prototype);
@@ -247,32 +260,33 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
Q_ASSERT(index == FunctionObject::Index_ProtoConstructor);
RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(objectClass);
- regExpClass = emptyClass->changePrototype(regExpPrototype);
+ regExpClass = InternalClass::create(this, &RegExpObject::static_vtbl, regExpPrototype);
regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(objectClass);
- errorClass = emptyClass->changePrototype(errorPrototype);
+ errorClass = InternalClass::create(this, &ErrorObject::static_vtbl, errorPrototype);
EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass);
- evalErrorClass = emptyClass->changePrototype(evalErrorPrototype);
+ evalErrorClass = InternalClass::create(this, &EvalErrorObject::static_vtbl, evalErrorPrototype);
RangeErrorPrototype *rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(errorClass);
- rangeErrorClass = emptyClass->changePrototype(rangeErrorPrototype);
+ rangeErrorClass = InternalClass::create(this, &RangeErrorObject::static_vtbl, rangeErrorPrototype);
ReferenceErrorPrototype *referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(errorClass);
- referenceErrorClass = emptyClass->changePrototype(referenceErrorPrototype);
+ referenceErrorClass = InternalClass::create(this, &ReferenceErrorObject::static_vtbl, referenceErrorPrototype);
SyntaxErrorPrototype *syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(errorClass);
- syntaxErrorClass = emptyClass->changePrototype(syntaxErrorPrototype);
+ syntaxErrorClass = InternalClass::create(this, &SyntaxErrorObject::static_vtbl, syntaxErrorPrototype);
TypeErrorPrototype *typeErrorPrototype = new (memoryManager) TypeErrorPrototype(errorClass);
- typeErrorClass = emptyClass->changePrototype(typeErrorPrototype);
+ typeErrorClass = InternalClass::create(this, &TypeErrorObject::static_vtbl, typeErrorPrototype);
URIErrorPrototype *uRIErrorPrototype = new (memoryManager) URIErrorPrototype(errorClass);
- uriErrorClass = emptyClass->changePrototype(uRIErrorPrototype);
+ uriErrorClass = InternalClass::create(this, &URIErrorObject::static_vtbl, uRIErrorPrototype);
- VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(objectClass);
- variantClass = emptyClass->changePrototype(variantPrototype);
+ VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(InternalClass::create(this, &VariantPrototype::static_vtbl, objectPrototype));
+ variantClass = InternalClass::create(this, &VariantObject::static_vtbl, variantPrototype);
+ Q_ASSERT(variantClass->prototype == variantPrototype);
+ Q_ASSERT(variantPrototype->internalClass->prototype == objectPrototype);
- SequencePrototype *sequencePrototype = new (memoryManager) SequencePrototype(arrayClass->changePrototype(arrayPrototype));
- sequenceClass = emptyClass->changePrototype(sequencePrototype);
+ sequencePrototype = new (memoryManager) SequencePrototype(arrayClass);
objectCtor = new (memoryManager) ObjectCtor(rootContext);
stringCtor = new (memoryManager) StringCtor(rootContext);
@@ -307,7 +321,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
uRIErrorPrototype->init(this, uRIErrorCtor);
variantPrototype->init();
- sequencePrototype->init();
+ static_cast<SequencePrototype *>(sequencePrototype.managed())->init();
//
// set up the global object
@@ -315,6 +329,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
globalObject = newObject()->getPointer();
rootContext->global = globalObject;
rootContext->callData->thisObject = globalObject;
+ Q_ASSERT(globalObject->internalClass->vtable);
globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor);
globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor);
@@ -390,10 +405,12 @@ void ExecutionEngine::enableDebugger()
void ExecutionEngine::initRootContext()
{
rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData)));
- rootContext->init();
- current = rootContext;
- current->parent = 0;
- rootContext->initGlobalContext(this);
+ new (rootContext) GlobalContext(this);
+ rootContext->callData = reinterpret_cast<CallData *>(rootContext + 1);
+ rootContext->callData->tag = QV4::Value::_Integer_Type;
+ rootContext->callData->argc = 0;
+ rootContext->callData->thisObject = globalObject;
+ rootContext->callData->args[0] = Encode::undefined();
}
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
@@ -403,14 +420,11 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
ExecutionContext *ExecutionEngine::pushGlobalContext()
{
- GlobalContext *g = new (memoryManager) GlobalContext;
- ExecutionContext *oldNext = g->next;
- memcpy(g, rootContext, sizeof(GlobalContext));
- g->next = oldNext;
- g->parent = current;
- current = g;
+ GlobalContext *g = new (memoryManager) GlobalContext(this);
+ g->callData = rootContext->callData;
- return current;
+ Q_ASSERT(currentContext() == g);
+ return g;
}
Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
@@ -598,7 +612,7 @@ Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ct
Returned<Object> *ExecutionEngine::qmlContextObject() const
{
- ExecutionContext *ctx = current;
+ ExecutionContext *ctx = currentContext();
if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
ctx = ctx->parent;
@@ -644,7 +658,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
QVector<StackFrame> stack;
- QV4::ExecutionContext *c = current;
+ QV4::ExecutionContext *c = currentContext();
while (c && frameLimit) {
CallContext *callCtx = c->asCallContext();
if (callCtx && callCtx->function) {
@@ -698,7 +712,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
return src;
QUrl base;
- QV4::ExecutionContext *c = current;
+ QV4::ExecutionContext *c = currentContext();
while (c) {
CallContext *callCtx = c->asCallContext();
if (callCtx && callCtx->function) {
@@ -754,7 +768,7 @@ void ExecutionEngine::markObjects()
setter->mark(this);
}
- ExecutionContext *c = current;
+ ExecutionContext *c = currentContext();
while (c) {
c->mark(this);
c = c->parent;
@@ -796,6 +810,7 @@ void ExecutionEngine::markObjects()
syntaxErrorCtor.mark(this);
typeErrorCtor.mark(this);
uRIErrorCtor.mark(this);
+ sequencePrototype.mark(this);
exceptionValue.mark(this);
@@ -816,13 +831,13 @@ namespace {
{
bool operator()(Function *function, quintptr pc)
{
- return reinterpret_cast<quintptr>(function->codePtr) < pc
- && (reinterpret_cast<quintptr>(function->codePtr) + function->codeSize) < pc;
+ return reinterpret_cast<quintptr>(function->code) < pc
+ && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc;
}
bool operator()(quintptr pc, Function *function)
{
- return pc < reinterpret_cast<quintptr>(function->codePtr);
+ return pc < reinterpret_cast<quintptr>(function->code);
}
};
}
@@ -889,8 +904,8 @@ ReturnedValue ExecutionEngine::throwException(const ValueRef value)
ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace)
{
Q_ASSERT(hasException);
- while (current != catchingContext)
- popContext();
+ Q_UNUSED(catchingContext);
+ Q_ASSERT(currentContext() == catchingContext);
if (trace)
*trace = exceptionStackTrace;
exceptionStackTrace.clear();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index c37d4f125d..ecb5f2b4d5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -44,7 +44,6 @@
#include "qv4global_p.h"
#include "private/qv4isel_p.h"
#include "qv4util_p.h"
-#include "qv4context_p.h"
#include "qv4property_p.h"
#include <private/qintrusivelist_p.h>
@@ -112,11 +111,12 @@ class RegExp;
class RegExpCache;
struct QmlExtensions;
struct Exception;
+struct ExecutionContextSaver;
#define CHECK_STACK_LIMITS(v4) \
if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \
else \
- return v4->current->throwRangeError(QStringLiteral("Maximum call stack size exceeded."))
+ return v4->currentContext()->throwRangeError(QStringLiteral("Maximum call stack size exceeded."))
struct Q_QML_EXPORT ExecutionEngine
@@ -126,7 +126,13 @@ struct Q_QML_EXPORT ExecutionEngine
ExecutableAllocator *regExpAllocator;
QScopedPointer<QQmlJS::EvalISelFactory> iselFactory;
+private:
+ friend struct ExecutionContextSaver;
+ friend struct ExecutionContext;
ExecutionContext *current;
+public:
+ ExecutionContext *currentContext() const { return current; }
+
GlobalContext *rootContext;
SafeValue *jsStackTop;
@@ -183,12 +189,16 @@ struct Q_QML_EXPORT ExecutionEngine
SafeValue syntaxErrorCtor;
SafeValue typeErrorCtor;
SafeValue uRIErrorCtor;
+ SafeValue sequencePrototype;
QQmlJS::MemoryPool classPool;
InternalClass *emptyClass;
+ InternalClass *executionContextClass;
+ InternalClass *stringClass;
+
InternalClass *objectClass;
InternalClass *arrayClass;
- InternalClass *stringClass;
+ InternalClass *stringObjectClass;
InternalClass *booleanClass;
InternalClass *numberClass;
InternalClass *dateClass;
@@ -199,6 +209,7 @@ struct Q_QML_EXPORT ExecutionEngine
InternalClass *regExpClass;
InternalClass *regExpExecArrayClass;
+ InternalClass *regExpValueClass;
InternalClass *errorClass;
InternalClass *evalErrorClass;
@@ -211,7 +222,6 @@ struct Q_QML_EXPORT ExecutionEngine
InternalClass *strictArgumentsObjectClass;
InternalClass *variantClass;
- InternalClass *sequenceClass;
EvalFunction *evalFunction;
FunctionObject *thrower;
@@ -356,35 +366,6 @@ private:
QmlExtensions *m_qmlExtensions;
};
-inline void ExecutionEngine::pushContext(CallContext *context)
-{
- context->parent = current;
- current = context;
- current->currentEvalCode = 0;
-}
-
-inline ExecutionContext *ExecutionEngine::popContext()
-{
- current = current->parent;
- return current;
-}
-
-struct ExecutionContextSaver
-{
- ExecutionEngine *engine;
- ExecutionContext *savedContext;
-
- ExecutionContextSaver(ExecutionContext *context)
- : engine(context->engine)
- , savedContext(context)
- {
- }
- ~ExecutionContextSaver()
- {
- engine->current = savedContext;
- }
-};
-
inline
void Managed::mark(QV4::ExecutionEngine *engine)
{
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index bac29d19e1..cf5c06dd41 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -77,7 +77,6 @@ ErrorObject::ErrorObject(InternalClass *ic)
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
Scope scope(engine());
ScopedValue protectThis(scope, this);
@@ -91,7 +90,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t)
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -116,7 +114,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject:
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -141,7 +138,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -207,13 +203,11 @@ DEFINE_MANAGED_VTABLE(SyntaxErrorObject);
SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg)
: ErrorObject(engine->syntaxErrorClass, msg, SyntaxError)
{
- vtbl = &static_vtbl;
}
SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
: ErrorObject(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError)
{
- vtbl = &static_vtbl;
}
EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const ValueRef message)
@@ -272,13 +266,13 @@ DEFINE_MANAGED_VTABLE(URIErrorCtor);
ErrorCtor::ErrorCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Error"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ErrorCtor::ErrorCtor(ExecutionContext *scope, const QString &name)
: FunctionObject(scope, name)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData)
@@ -296,7 +290,7 @@ ReturnedValue ErrorCtor::call(Managed *that, CallData *callData)
EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("EvalError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData)
@@ -309,7 +303,7 @@ ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData)
RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("RangeError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData)
@@ -322,7 +316,7 @@ ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData)
ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("ReferenceError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData)
@@ -335,7 +329,7 @@ ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData)
SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("SyntaxError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData)
@@ -348,7 +342,7 @@ ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData)
TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("TypeError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData)
@@ -361,7 +355,7 @@ ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData)
URIErrorCtor::URIErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("URIError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 3f4cb8fc43..def776d3b6 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -184,37 +184,37 @@ struct ErrorPrototype: ErrorObject
struct EvalErrorPrototype: ErrorObject
{
- EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct RangeErrorPrototype: ErrorObject
{
- RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct ReferenceErrorPrototype: ErrorObject
{
- ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct SyntaxErrorPrototype: ErrorObject
{
- SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct TypeErrorPrototype: ErrorObject
{
- TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct URIErrorPrototype: ErrorObject
{
- URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ebe214ad72..0e90e213c4 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -54,7 +54,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize)
: compiledFunction(function)
, compilationUnit(unit)
- , codePtr(codePtr)
+ , code(codePtr)
, codeData(0)
, codeSize(_codeSize)
{
@@ -62,18 +62,29 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
name = compilationUnit->runtimeStrings[compiledFunction->nameIndex].asString();
- formals.resize(compiledFunction->nFormals);
- formals.fill(0);
- const quint32 *formalsIndices = compiledFunction->formalsTable();
- for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
- formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
+ nArguments = compiledFunction->nFormals;
+ internalClass = engine->emptyClass;
+ const quint32 *formalsIndices = compiledFunction->formalsTable();
+ // iterate backwards, so we get the right ordering for duplicate names
+ for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) {
+ String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
+ while (1) {
+ InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable);
+ if (newClass != internalClass) {
+ internalClass = newClass;
+ break;
+ }
+ // duplicate arguments, need some trick to store them
+ arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer());
+ }
+ }
- locals.resize(compiledFunction->nLocals);
- locals.fill(0);
const quint32 *localsIndices = compiledFunction->localsTable();
- for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
- locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString();
+ for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
+ String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString();
+ internalClass = internalClass->addMember(local, Attr_NotConfigurable);
+ }
}
Function::~Function()
@@ -84,10 +95,6 @@ Function::~Function()
void Function::mark(ExecutionEngine *e)
{
name.mark(e);
- for (int i = 0; i < formals.size(); ++i)
- formals.at(i)->mark(e);
- for (int i = 0; i < locals.size(); ++i)
- locals.at(i)->mark(e);
}
namespace QV4 {
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 5d284f1b2b..8d07853b45 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -85,16 +85,14 @@ struct Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
- inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) {
- return codePtr(ctx, data);
- }
- ReturnedValue (*codePtr)(ExecutionContext *, const uchar *);
+ ReturnedValue (*code)(ExecutionContext *, const uchar *);
const uchar *codeData;
quint32 codeSize;
- QVector<String *> formals;
- QVector<String *> locals;
+ // first nArguments names in internalClass are the actual arguments
+ int nArguments;
+ InternalClass *internalClass;
Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 037f06cd35..6e5c137e0b 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -76,11 +76,11 @@ DEFINE_MANAGED_VTABLE(FunctionObject);
FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
init(name, createProto);
}
@@ -88,11 +88,11 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bo
FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
// set the name to something here, so that a gc run a few lines below doesn't crash on it
this->name = scope->engine->id_undefined;
@@ -106,13 +106,10 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, boo
FunctionObject::FunctionObject(InternalClass *ic)
: Object(ic)
, scope(ic->engine->rootContext)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
{
- vtbl = &static_vtbl;
name = ic->engine->id_undefined;
type = Type_FunctionObject;
@@ -128,7 +125,6 @@ FunctionObject::~FunctionObject()
void FunctionObject::init(const StringRef n, bool createProto)
{
- vtbl = &static_vtbl;
name = n;
Scope s(internalClass->engine);
@@ -158,43 +154,13 @@ ReturnedValue FunctionObject::newInstance()
return construct(callData);
}
-bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
-{
- Scope scope(that->internalClass->engine);
- ScopedFunctionObject f(scope, static_cast<FunctionObject *>(that));
-
- ScopedObject v(scope, value);
- if (!v)
- return false;
-
- Scoped<Object> o(scope, f->get(scope.engine->id_prototype));
- if (!o) {
- scope.engine->current->throwTypeError();
- return false;
- }
-
- while (v) {
- v = v->prototype();
-
- if (! v)
- break;
- else if (o.getPointer() == v)
- return true;
- }
-
- return false;
-}
-
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
{
ExecutionEngine *v4 = that->internalClass->engine;
Scope scope(v4);
Scoped<FunctionObject> f(scope, that, Scoped<FunctionObject>::Cast);
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->get(v4->id_prototype));
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
Scoped<Object> obj(scope, v4->newObject(ic));
return obj.asReturnedValue();
}
@@ -231,13 +197,49 @@ FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Fun
return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function);
}
+ReturnedValue FunctionObject::protoProperty()
+{
+ if (protoCacheClass != internalClass) {
+ protoCacheClass = internalClass;
+ protoCacheIndex = internalClass->find(internalClass->engine->id_prototype);
+ }
+ if (protoCacheIndex < UINT_MAX) {
+ if (internalClass->propertyData.at(protoCacheIndex).isData()) {
+ ReturnedValue v = memberData[protoCacheIndex].value.asReturnedValue();
+ if (v != protoValue) {
+ classForConstructor = 0;
+ protoValue = v;
+ }
+ return v;
+ }
+ }
+ classForConstructor = 0;
+ return get(internalClass->engine->id_prototype);
+}
+
+InternalClass *FunctionObject::internalClassForConstructor()
+{
+ // need to call this first to ensure we don't use a wrong class
+ ReturnedValue proto = protoProperty();
+ if (classForConstructor)
+ return classForConstructor;
+
+ Scope scope(internalClass->engine);
+ ScopedObject p(scope, proto);
+ if (p)
+ classForConstructor = InternalClass::create(scope.engine, &Object::static_vtbl, p.getPointer());
+ else
+ classForConstructor = scope.engine->objectClass;
+
+ return classForConstructor;
+}
DEFINE_MANAGED_VTABLE(FunctionCtor);
FunctionCtor::FunctionCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Function"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
// 15.3.2
@@ -245,7 +247,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
{
FunctionCtor *f = static_cast<FunctionCtor *>(that);
ExecutionEngine *v4 = f->internalClass->engine;
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
QString arguments;
QString body;
if (callData->argc > 0) {
@@ -269,16 +271,16 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
if (!parsed)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
if (!fe)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
QQmlJS::V4IR::Module module(v4->debugger != 0);
- QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
+ QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
@@ -402,7 +404,7 @@ DEFINE_MANAGED_VTABLE(ScriptFunction);
ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -410,7 +412,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -420,12 +422,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -444,13 +444,10 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- ScopedObject proto(scope, f->memberData[Index_Prototype].value);
- if (proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
ScopedObject obj(scope, v4->newObject(ic));
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
@@ -472,7 +469,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
Scope scope(context);
CallContext *ctx = context->newCallContext(f, callData);
@@ -489,7 +486,7 @@ DEFINE_MANAGED_VTABLE(SimpleScriptFunction);
SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -497,7 +494,7 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -507,12 +504,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -531,33 +526,29 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->memberData[Index_Prototype].value);
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
callData->thisObject = v4->newObject(ic);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f.getPointer();
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
Scoped<Object> result(scope, f->function->code(&ctx, f->function->codeData));
if (!result)
@@ -575,27 +566,26 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
Scope scope(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f;
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->current = &ctx;
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
return f->function->code(&ctx, f->function->codeData);
}
@@ -608,12 +598,12 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
: FunctionObject(scope, name)
, code(code)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
{
- return f->internalClass->engine->current->throwTypeError();
+ return f->internalClass->engine->currentContext()->throwTypeError();
}
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
@@ -624,15 +614,14 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx);
}
@@ -644,16 +633,14 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
- Scope scope(v4);
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx, f->index);
}
@@ -666,7 +653,8 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target,
, target(target)
, boundArgs(boundArgs)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
+ subtype = FunctionObject::BoundFunction;
this->boundThis = boundThis;
Scope s(scope);
@@ -718,12 +706,6 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
return f->target->construct(callData);
}
-bool BoundFunction::hasInstance(Managed *that, const ValueRef value)
-{
- BoundFunction *f = static_cast<BoundFunction *>(that);
- return FunctionObject::hasInstance(f->target, value);
-}
-
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
{
BoundFunction *o = static_cast<BoundFunction *>(that);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 2fc36d862f..96534cb68c 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -97,7 +97,8 @@ struct Q_QML_EXPORT FunctionObject: Object {
// Used with Managed::subType
enum FunctionType {
RegularFunction = 0,
- WrappedQtMethod = 1
+ WrappedQtMethod = 1,
+ BoundFunction
};
enum {
@@ -107,11 +108,13 @@ struct Q_QML_EXPORT FunctionObject: Object {
ExecutionContext *scope;
SafeString name;
- String * const *formalParameterList;
- String * const *varList;
unsigned int formalParameterCount;
unsigned int varCount;
Function *function;
+ InternalClass *protoCacheClass;
+ uint protoCacheIndex;
+ ReturnedValue protoValue;
+ InternalClass *classForConstructor;
FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false);
FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false);
@@ -124,10 +127,10 @@ struct Q_QML_EXPORT FunctionObject: Object {
static ReturnedValue construct(Managed *that, CallData *);
static ReturnedValue call(Managed *that, CallData *d);
inline ReturnedValue construct(CallData *callData) {
- return vtbl->construct(this, callData);
+ return internalClass->vtable->construct(this, callData);
}
inline ReturnedValue call(CallData *callData) {
- return vtbl->call(this, callData);
+ return internalClass->vtable->call(this, callData);
}
static FunctionObject *cast(const Value &v) {
@@ -136,11 +139,13 @@ struct Q_QML_EXPORT FunctionObject: Object {
static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function);
+ ReturnedValue protoProperty();
+ InternalClass *internalClassForConstructor();
+
protected:
FunctionObject(InternalClass *ic);
static void markObjects(Managed *that, ExecutionEngine *e);
- static bool hasInstance(Managed *that, const ValueRef value);
static void destroy(Managed *that)
{ static_cast<FunctionObject*>(that)->~FunctionObject(); }
};
@@ -192,12 +197,12 @@ struct IndexedBuiltinFunction: FunctionObject
, code(code)
, index(index)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static ReturnedValue construct(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
static ReturnedValue call(Managed *that, CallData *callData);
@@ -235,7 +240,6 @@ struct BoundFunction: FunctionObject {
static void destroy(Managed *);
static void markObjects(Managed *that, ExecutionEngine *e);
- static bool hasInstance(Managed *that, const ValueRef value);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 7d7338f19c..1d465df0c0 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -119,6 +119,8 @@ struct Object;
struct ObjectPrototype;
struct ObjectIterator;
struct ExecutionContext;
+struct GlobalContext;
+struct CallContext;
struct ScriptFunction;
struct InternalClass;
struct Property;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 82622de5bb..fa8af8ed5d 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -349,7 +349,7 @@ DEFINE_MANAGED_VTABLE(EvalFunction);
EvalFunction::EvalFunction(ExecutionContext *scope)
: FunctionObject(scope, scope->engine->id_eval)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
}
@@ -379,15 +379,17 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
if (callData->argc < 1)
return Encode::undefined();
- ExecutionContext *parentContext = engine()->current;
- ExecutionEngine *engine = parentContext->engine;
+ ExecutionEngine *v4 = engine();
+ ExecutionContext *parentContext = v4->currentContext();
+ ExecutionContextSaver ctxSaver(parentContext);
+
ExecutionContext *ctx = parentContext;
Scope scope(ctx);
if (!directCall) {
// the context for eval should be the global scope, so we fake a root
// context
- ctx = engine->pushGlobalContext();
+ ctx = v4->pushGlobalContext();
}
if (!callData->args[0].isString())
@@ -418,7 +420,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
return e->call(callData);
}
- ExecutionContextSaver ctxSaver(parentContext);
ContextStateSaver stateSaver(ctx);
ExecutionContext::EvalCode evalCode;
@@ -437,7 +438,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
ReturnedValue EvalFunction::call(Managed *that, CallData *callData)
{
// indirect call
- // ### const_cast
return static_cast<EvalFunction *>(that)->evalCall(callData, false);
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 8f2548064a..d0e0e9413b 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -108,7 +108,7 @@ void QV4Include::callback(const QV4::ValueRef callback, const QV4::ValueRef stat
if (!f)
return;
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = v4->globalObject->asReturnedValue();
callData->args[0] = status;
@@ -153,7 +153,7 @@ void QV4Include::finished()
QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value());
QV4::Script script(v4, qmlglobal, code, m_url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedString status(scope, v4->newString(QStringLiteral("status")));
script.parse();
if (!scope.engine->hasException)
@@ -220,7 +220,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
QV4::Script script(v4, qmlcontextobject, code, url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
script.parse();
if (!v4->hasException)
script.run();
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index cb799a473c..29ede3d104 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -126,10 +126,21 @@ uint PropertyHash::lookup(const Identifier *identifier) const
}
}
+InternalClass::InternalClass(ExecutionEngine *engine)
+ : engine(engine)
+ , prototype(0)
+ , vtable(&Managed::static_vtbl)
+ , m_sealed(0)
+ , m_frozen(0)
+ , size(0)
+{
+}
+
InternalClass::InternalClass(const QV4::InternalClass &other)
: engine(other.engine)
, prototype(other.prototype)
+ , vtable(other.vtable)
, propertyTable(other.propertyTable)
, nameMap(other.nameMap)
, propertyData(other.propertyData)
@@ -169,6 +180,12 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
}
+InternalClass *InternalClass::create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto)
+{
+ InternalClass *c = engine->emptyClass->changeVTable(vtable);
+ return c->changePrototype(proto);
+}
+
InternalClass *InternalClass::changePrototype(Object *proto)
{
if (prototype == proto)
@@ -184,11 +201,41 @@ InternalClass *InternalClass::changePrototype(Object *proto)
// create a new class and add it to the tree
InternalClass *newClass;
- if (this == engine->emptyClass) {
+ if (!size) {
newClass = engine->newClass(*this);
newClass->prototype = proto;
} else {
- newClass = engine->emptyClass->changePrototype(proto);
+ newClass = engine->emptyClass->changeVTable(vtable);
+ newClass = newClass->changePrototype(proto);
+ for (uint i = 0; i < size; ++i)
+ newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ }
+
+ transitions.insert(t, newClass);
+ return newClass;
+}
+
+InternalClass *InternalClass::changeVTable(const ManagedVTable *vt)
+{
+ if (vtable == vt)
+ return this;
+
+ Transition t;
+ t.vtable = vt;
+ t.flags = Transition::VTableChange;
+
+ QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
+ if (tit != transitions.constEnd())
+ return tit.value();
+
+ // create a new class and add it to the tree
+ InternalClass *newClass;
+ if (this == engine->emptyClass) {
+ newClass = engine->newClass(*this);
+ newClass->vtable = vt;
+ } else {
+ newClass = engine->emptyClass->changeVTable(vt);
+ newClass = newClass->changePrototype(prototype);
for (uint i = 0; i < size; ++i)
newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
}
@@ -250,7 +297,8 @@ void InternalClass::removeMember(Object *object, Identifier *id)
}
// create a new class and add it to the tree
- object->internalClass = engine->emptyClass->changePrototype(prototype);
+ object->internalClass = engine->emptyClass->changeVTable(vtable);
+ object->internalClass = object->internalClass->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
if (i == propIdx)
continue;
@@ -283,6 +331,7 @@ InternalClass *InternalClass::sealed()
return m_sealed;
m_sealed = engine->emptyClass;
+ m_sealed = m_sealed->changeVTable(vtable);
m_sealed = m_sealed->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
@@ -300,6 +349,7 @@ InternalClass *InternalClass::frozen()
return m_frozen;
m_frozen = engine->emptyClass;
+ m_frozen = m_frozen->changeVTable(vtable);
m_frozen = m_frozen->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
@@ -343,7 +393,9 @@ void InternalClass::markObjects()
for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
it != end; ++it) {
- if (it.key().flags == Transition::ProtoChange) {
+ if (it.key().flags == Transition::VTableChange) {
+ it.value()->markObjects();
+ } else if (it.key().flags == Transition::ProtoChange) {
Q_ASSERT(it.value()->prototype);
it.value()->prototype->mark(engine);
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 9586637b32..b25b895183 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -53,6 +53,7 @@ struct String;
struct ExecutionEngine;
struct Object;
struct Identifier;
+struct ManagedVTable;
struct PropertyHashData;
struct PropertyHash
@@ -198,9 +199,14 @@ struct InternalClassTransition
union {
Identifier *id;
Object *prototype;
+ const ManagedVTable *vtable;
};
int flags;
- enum { ProtoChange = 0x100 };
+ enum {
+ // range 0-0xff is reserved for attribute changes
+ ProtoChange = 0x100,
+ VTableChange = 0x200
+ };
bool operator==(const InternalClassTransition &other) const
{ return id == other.id && flags == other.flags; }
@@ -210,6 +216,8 @@ uint qHash(const QV4::InternalClassTransition &t, uint = 0);
struct InternalClass {
ExecutionEngine *engine;
Object *prototype;
+ const ManagedVTable *vtable;
+
PropertyHash propertyTable; // id to valueIndex
SharedInternalClassData<String *> nameMap;
SharedInternalClassData<PropertyAttributes> propertyData;
@@ -222,7 +230,9 @@ struct InternalClass {
uint size;
+ static InternalClass *create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto);
InternalClass *changePrototype(Object *proto);
+ InternalClass *changeVTable(const ManagedVTable *vt);
InternalClass *addMember(StringRef string, PropertyAttributes data, uint *index = 0);
InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
@@ -238,7 +248,7 @@ struct InternalClass {
private:
friend struct ExecutionEngine;
- InternalClass(ExecutionEngine *engine) : engine(engine), prototype(0), m_sealed(0), m_frozen(0), size(0) {}
+ InternalClass(ExecutionEngine *engine);
InternalClass(const InternalClass &other);
};
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 458b46b36e..6633435668 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -284,8 +284,13 @@ bool JsonParser::parseMember(ObjectRef o)
return false;
ScopedString s(scope, context->engine->newIdentifier(key));
- Property *p = o->insertMember(s, Attr_Data);
- p->value = val.asReturnedValue();
+ uint idx = s->asArrayIndex();
+ if (idx < UINT_MAX) {
+ o->putIndexed(idx, val);
+ } else {
+ Property *p = o->insertMember(s, Attr_Data);
+ p->value = val.asReturnedValue();
+ }
END;
return true;
@@ -960,7 +965,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value)
{
if (value.isString())
- return engine->current->engine->newString(value.toString())->asReturnedValue();
+ return engine->currentContext()->engine->newString(value.toString())->asReturnedValue();
else if (value.isDouble())
return Encode(value.toDouble());
else if (value.isBool())
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index f63e7726f5..3bcbdeadbf 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -38,8 +38,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QV4JSONOBJECTS_H
-#define QV4SJONOBJECTS_H
+#ifndef QV4JSONOBJECT_H
+#define QV4JSONOBJECT_H
#include "qv4object_p.h"
#include <qjsonarray.h>
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index f67b24c040..a870cdac61 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -87,13 +87,13 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
switch (object->type()) {
case Value::Undefined_Type:
case Value::Null_Type:
- return engine->current->throwTypeError();
+ return engine->currentContext()->throwTypeError();
case Value::Boolean_Type:
proto = engine->booleanClass->prototype;
break;
case Value::Managed_Type:
Q_ASSERT(object->isString());
- proto = engine->stringClass->prototype;
+ proto = engine->stringObjectClass->prototype;
if (l->name->equals(engine->id_length)) {
// special case, as the property is on the object itself
l->getter = stringLengthGetter;
@@ -446,7 +446,7 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu
Scope scope(l->name->engine());
ScopedObject o(scope, object);
if (!o) {
- o = __qmljs_convert_to_object(scope.engine->current, object);
+ o = __qmljs_convert_to_object(scope.engine->currentContext(), object);
if (!o) // type error
return;
ScopedString s(scope, l->name);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 6455a08037..fef7489110 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -52,7 +52,6 @@ const ManagedVTable Managed::static_vtbl =
0 /*markObjects*/,
destroy,
0 /*collectDeletables*/,
- hasInstance,
0,
0,
0,
@@ -82,7 +81,6 @@ void Managed::operator delete(void *ptr)
return;
Managed *m = static_cast<Managed *>(ptr);
- m->vtbl = 0;
m->_data = 0;
m->markBit = 0;
m->~Managed();
@@ -178,29 +176,30 @@ QString Managed::className() const
return QString::fromLatin1(s);
}
-bool Managed::hasInstance(Managed *m, const ValueRef)
+void Managed::setVTable(const ManagedVTable *vt)
{
- return m->engine()->current->throwTypeError();
+ Q_ASSERT(internalClass);
+ internalClass = internalClass->changeVTable(vt);
}
ReturnedValue Managed::construct(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
ReturnedValue Managed::call(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
ReturnedValue Managed::getLookup(Managed *m, Lookup *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
void Managed::setLookup(Managed *m, Lookup *, const ValueRef)
{
- m->engine()->current->throwTypeError();
+ m->engine()->currentContext()->throwTypeError();
}
bool Managed::isEqualTo(Managed *, Managed *)
@@ -208,47 +207,42 @@ bool Managed::isEqualTo(Managed *, Managed *)
return false;
}
-bool Managed::hasInstance(const ValueRef v)
-{
- return vtbl->hasInstance(this, v);
-}
-
ReturnedValue Managed::get(const StringRef name, bool *hasProperty)
{
- return vtbl->get(this, name, hasProperty);
+ return internalClass->vtable->get(this, name, hasProperty);
}
ReturnedValue Managed::getIndexed(uint index, bool *hasProperty)
{
- return vtbl->getIndexed(this, index, hasProperty);
+ return internalClass->vtable->getIndexed(this, index, hasProperty);
}
void Managed::put(const StringRef name, const ValueRef value)
{
- vtbl->put(this, name, value);
+ internalClass->vtable->put(this, name, value);
}
void Managed::setLookup(Lookup *l, const ValueRef v)
{
- vtbl->setLookup(this, l, v);
+ internalClass->vtable->setLookup(this, l, v);
}
void Managed::putIndexed(uint index, const ValueRef value)
{
- vtbl->putIndexed(this, index, value);
+ internalClass->vtable->putIndexed(this, index, value);
}
PropertyAttributes Managed::query(StringRef name) const
{
- return vtbl->query(this, name);
+ return internalClass->vtable->query(this, name);
}
bool Managed::deleteProperty(const StringRef name)
{
- return vtbl->deleteProperty(this, name);
+ return internalClass->vtable->deleteProperty(this, name);
}
Property *Managed::advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes)
{
- return vtbl->advanceIterator(this, it, name, index, attributes);
+ return internalClass->vtable->advanceIterator(this, it, name, index, attributes);
}
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 47ac5e05e4..63972688a7 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -46,6 +46,7 @@
#include <QtCore/QDebug>
#include "qv4global_p.h"
#include "qv4value_def_p.h"
+#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
@@ -84,7 +85,6 @@ struct ManagedVTable
void (*markObjects)(Managed *, ExecutionEngine *e);
void (*destroy)(Managed *);
void (*collectDeletables)(Managed *, GCDeletable **deletable);
- bool (*hasInstance)(Managed *, const ValueRef value);
ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty);
ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty);
void (*put)(Managed *, const StringRef name, const ValueRef value);
@@ -108,7 +108,6 @@ const QV4::ManagedVTable classname::static_vtbl = \
markObjects, \
destroy, \
0, \
- hasInstance, \
get, \
getIndexed, \
put, \
@@ -132,7 +131,6 @@ const QV4::ManagedVTable classname::static_vtbl = \
markObjects, \
destroy, \
collectDeletables, \
- hasInstance, \
get, \
getIndexed, \
put, \
@@ -158,11 +156,15 @@ private:
protected:
Managed(InternalClass *internal)
- : _data(0), vtbl(&static_vtbl), internalClass(internal)
- { inUse = 1; extensible = 1; }
+ : internalClass(internal), _data(0)
+ {
+ Q_ASSERT(!internalClass || internalClass->vtable);
+ inUse = 1; extensible = 1;
+ }
public:
void *operator new(size_t size, MemoryManager *mm);
+ void *operator new(size_t, Managed *m) { return m; }
void operator delete(void *ptr);
void operator delete(void *ptr, MemoryManager *mm);
@@ -194,12 +196,12 @@ public:
template <typename T>
T *as() {
// ### FIXME:
- if (!this)
+ if (!this || !internalClass)
return 0;
#if !defined(QT_NO_QOBJECT_CHECK)
reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(this));
#endif
- return vtbl == &T::static_vtbl ? static_cast<T *>(this) : 0;
+ return internalClass->vtable == &T::static_vtbl ? static_cast<T *>(this) : 0;
}
template <typename T>
const T *as() const {
@@ -209,7 +211,7 @@ public:
#if !defined(QT_NO_QOBJECT_CHECK)
reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(const_cast<Managed *>(this)));
#endif
- return vtbl == &T::static_vtbl ? static_cast<const T *>(this) : 0;
+ return internalClass->vtable == &T::static_vtbl ? static_cast<const T *>(this) : 0;
}
String *asString() { return type == Type_String ? reinterpret_cast<String *>(this) : 0; }
@@ -240,7 +242,8 @@ public:
*reinterpret_cast<Managed **>(this) = m;
}
- bool hasInstance(const ValueRef v);
+ void setVTable(const ManagedVTable *vt);
+
ReturnedValue construct(CallData *d);
ReturnedValue call(CallData *d);
ReturnedValue get(const StringRef name, bool *hasProperty = 0);
@@ -249,21 +252,20 @@ public:
void putIndexed(uint index, const ValueRef value);
PropertyAttributes query(StringRef name) const;
PropertyAttributes queryIndexed(uint index) const
- { return vtbl->queryIndexed(this, index); }
+ { return internalClass->vtable->queryIndexed(this, index); }
bool deleteProperty(const StringRef name);
bool deleteIndexedProperty(uint index)
- { return vtbl->deleteIndexedProperty(this, index); }
+ { return internalClass->vtable->deleteIndexedProperty(this, index); }
ReturnedValue getLookup(Lookup *l)
- { return vtbl->getLookup(this, l); }
+ { return internalClass->vtable->getLookup(this, l); }
void setLookup(Lookup *l, const ValueRef v);
bool isEqualTo(Managed *other)
- { return vtbl->isEqualTo(this, other); }
+ { return internalClass->vtable->isEqualTo(this, other); }
Property *advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
static void destroy(Managed *that) { that->_data = 0; }
- static bool hasInstance(Managed *that, const ValueRef value);
static ReturnedValue construct(Managed *m, CallData *d);
static ReturnedValue call(Managed *m, CallData *);
static ReturnedValue getLookup(Managed *m, Lookup *);
@@ -276,6 +278,9 @@ public:
ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); }
+
+ InternalClass *internalClass;
+
enum {
SimpleArray = 1
};
@@ -297,11 +302,6 @@ public:
};
};
-protected:
- const ManagedVTable *vtbl;
-public:
- InternalClass *internalClass;
-
private:
friend class MemoryManager;
friend struct Identifiers;
@@ -337,10 +337,10 @@ inline FunctionObject *managed_cast(Managed *m)
inline ReturnedValue Managed::construct(CallData *d) {
- return vtbl->construct(this, d);
+ return internalClass->vtable->construct(this, d);
}
inline ReturnedValue Managed::call(CallData *d) {
- return vtbl->call(this, d);
+ return internalClass->vtable->call(this, d);
}
}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index dca75e6c28..6fe3db3950 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -39,7 +39,7 @@
**
****************************************************************************/
#ifndef QV4MATHOBJECT_H
-#define QV$MATHOBJECT_H
+#define QV4MATHOBJECT_H
#include "qv4object_p.h"
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 0b15588ed4..f67efaffb9 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -424,8 +424,8 @@ void MemoryManager::mark()
// now that we marked all roots, start marking recursively and popping from the mark stack
while (m_d->engine->jsStackTop > markBase) {
Managed *m = m_d->engine->popForGC();
- Q_ASSERT (m->vtbl->markObjects);
- m->vtbl->markObjects(m, m_d->engine);
+ Q_ASSERT (m->internalClass->vtable->markObjects);
+ m->internalClass->vtable->markObjects(m, m_d->engine);
}
}
@@ -516,9 +516,9 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
- if (m->vtbl->collectDeletables)
- m->vtbl->collectDeletables(m, deletable);
- m->vtbl->destroy(m);
+ if (m->internalClass->vtable->collectDeletables)
+ m->internalClass->vtable->collectDeletables(m, deletable);
+ m->internalClass->vtable->destroy(m);
m->setNextFree(*f);
#ifdef V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 039b790aed..a363a06242 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -54,7 +54,7 @@ DEFINE_MANAGED_VTABLE(NumberObject);
NumberCtor::NumberCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Number"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue NumberCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 743d35fa69..106525d412 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -74,18 +74,17 @@ Object::Object(ExecutionEngine *engine)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
, arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
- vtbl = &static_vtbl;
type = Type_Object;
flags = SimpleArray;
memset(memberData, 0, sizeof(Property)*memberDataAlloc);
}
-Object::Object(InternalClass *internalClass)
- : Managed(internalClass)
+Object::Object(InternalClass *ic)
+ : Managed(ic)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
, arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
- vtbl = &static_vtbl;
+ Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
type = Type_Object;
flags = SimpleArray;
@@ -169,8 +168,8 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val
return;
reject:
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
}
void Object::defineDefaultProperty(const StringRef name, ValueRef value)
@@ -721,7 +720,7 @@ void Object::internalPut(const StringRef name, const ValueRef value)
bool ok;
uint l = value->asArrayLength(&ok);
if (!ok) {
- engine()->current->throwRangeError(value);
+ engine()->currentContext()->throwRangeError(value);
return;
}
ok = setArrayLength(l);
@@ -769,11 +768,11 @@ void Object::internalPut(const StringRef name, const ValueRef value)
}
reject:
- if (engine()->current->strictMode) {
+ if (engine()->currentContext()->strictMode) {
QString message = QStringLiteral("Cannot assign to read-only property \"");
message += name->toQString();
message += QLatin1Char('\"');
- engine()->current->throwTypeError(message);
+ engine()->currentContext()->throwTypeError(message);
}
}
@@ -844,8 +843,8 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
return;
reject:
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
}
// Section 8.12.7
@@ -867,8 +866,8 @@ bool Object::internalDeleteProperty(const StringRef name)
memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(Property));
return true;
}
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
return false;
}
@@ -897,8 +896,8 @@ bool Object::internalDeleteIndexedProperty(uint index)
return true;
}
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
return false;
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index daef18d4e2..23f2f682fd 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -280,13 +280,13 @@ public:
void ensureMemberIndex(uint idx);
inline ReturnedValue get(const StringRef name, bool *hasProperty = 0)
- { return vtbl->get(this, name, hasProperty); }
+ { return internalClass->vtable->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0)
- { return vtbl->getIndexed(this, idx, hasProperty); }
+ { return internalClass->vtable->getIndexed(this, idx, hasProperty); }
inline void put(const StringRef name, const ValueRef v)
- { vtbl->put(this, name, v); }
+ { internalClass->vtable->put(this, name, v); }
inline void putIndexed(uint idx, const ValueRef v)
- { vtbl->putIndexed(this, idx, v); }
+ { internalClass->vtable->putIndexed(this, idx, v); }
using Managed::get;
using Managed::getIndexed;
using Managed::put;
@@ -331,14 +331,13 @@ struct BooleanObject: Object {
SafeValue value;
BooleanObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->booleanClass) {
- vtbl = &static_vtbl;
type = Type_BooleanObject;
value = val;
}
protected:
BooleanObject(InternalClass *ic)
: Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_BooleanObject;
value = Encode(false);
}
@@ -349,14 +348,13 @@ struct NumberObject: Object {
SafeValue value;
NumberObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->numberClass) {
- vtbl = &static_vtbl;
type = Type_NumberObject;
value = val;
}
protected:
NumberObject(InternalClass *ic)
: Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_NumberObject;
value = Encode((int)0);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 19aedf3766..6c333b328c 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -89,7 +89,7 @@ struct ForEachIteratorObject: Object {
ObjectIterator it;
ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
: Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_ForeachIteratorObject;
}
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index f17bd7d5ba..7ca790b970 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -77,7 +77,7 @@ DEFINE_MANAGED_VTABLE(ObjectCtor);
ObjectCtor::ObjectCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Object"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData)
@@ -92,14 +92,14 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData)
obj->setPrototype(proto.getPointer());
return obj.asReturnedValue();
}
- return __qmljs_to_object(v4->current, ValueRef(&callData->args[0]));
+ return __qmljs_to_object(v4->currentContext(), ValueRef(&callData->args[0]));
}
ReturnedValue ObjectCtor::call(Managed *m, CallData *callData)
{
if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull())
return m->engine()->newObject()->asReturnedValue();
- return __qmljs_to_object(m->engine()->current, ValueRef(&callData->args[0]));
+ return __qmljs_to_object(m->engine()->currentContext(), ValueRef(&callData->args[0]));
}
void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 85e6878f7b..61f92a0f5c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -241,7 +241,7 @@ QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
: Object(engine)
, m_object(object)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedObject protectThis(scope, this);
@@ -668,7 +668,7 @@ QV4::ReturnedValue QObjectWrapper::get(Managed *m, const StringRef name, bool *h
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = m->engine();
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return that->getQmlProperty(v4->current, qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true);
+ return that->getQmlProperty(v4->currentContext(), qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true);
}
void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
@@ -680,10 +680,10 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
return;
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- if (!setQmlProperty(v4->current, qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
+ if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
}
}
@@ -763,7 +763,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
Q_ASSERT(v4);
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, This->function.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedCallData callData(scope, argCount);
callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
@@ -1337,7 +1337,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (returnType == QMetaType::UnknownType) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName);
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
if (data.hasArguments()) {
@@ -1351,12 +1351,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (!args) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
if (args[0] > callArgs->argc) {
QString error = QLatin1String("Insufficient arguments");
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
@@ -1455,7 +1455,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
candidate = RelatedMethod(object, candidate, dummy);
}
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
}
@@ -1726,7 +1726,7 @@ QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index
, m_object(object)
, m_index(index)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
subtype = WrappedQtMethod;
m_qmlGlobal = qmlGlobal;
}
@@ -1782,7 +1782,7 @@ ReturnedValue QObjectMethod::call(Managed *m, CallData *callData)
ReturnedValue QObjectMethod::callInternal(CallData *callData)
{
- ExecutionContext *context = engine()->current;
+ ExecutionContext *context = engine()->currentContext();
if (m_index == DestroyMethod)
return method_destroy(context, callData->args, callData->argc);
else if (m_index == ToStringMethod)
@@ -1847,7 +1847,7 @@ QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int
, m_object(object)
, m_signalIndex(signalIndex)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
DEFINE_MANAGED_VTABLE(QmlSignalHandler);
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 5ec63061dc..41ff9f9741 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -92,14 +92,13 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign
}
RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
- : Managed(engine->emptyClass)
+ : Managed(engine->regExpValueClass)
, m_pattern(pattern)
, m_cache(0)
, m_subPatternCount(0)
, m_ignoreCase(ignoreCase)
, m_multiLine(multiline)
{
- vtbl = &static_vtbl;
type = Type_RegExpObject;
if (!engine)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index a8597229c4..468fb34d76 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -142,7 +142,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
void RegExpObject::init(ExecutionEngine *engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_RegExpObject;
Scope scope(engine);
@@ -237,12 +237,12 @@ DEFINE_MANAGED_VTABLE(RegExpCtor);
RegExpCtor::RegExpCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("RegExp"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
{
- ExecutionContext *ctx = m->engine()->current;
+ ExecutionContext *ctx = m->engine()->currentContext();
Scope scope(ctx);
ScopedValue r(scope, callData->argument(0));
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 50fea04b2f..011607f0ba 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -300,12 +300,34 @@ ReturnedValue __qmljs_delete_name(ExecutionContext *ctx, const StringRef name)
QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
- Object *o = right->asObject();
- if (!o)
+ FunctionObject *f = right->asFunctionObject();
+ if (!f)
return ctx->throwTypeError();
- bool r = o->hasInstance(left);
- return Encode(r);
+ if (f->subtype == FunctionObject::BoundFunction)
+ f = static_cast<BoundFunction *>(f)->target;
+
+ Scope scope(ctx->engine);
+ ScopedObject v(scope, left);
+ if (!v)
+ return Encode(false);
+
+ Scoped<Object> o(scope, f->protoProperty());
+ if (!o) {
+ scope.engine->currentContext()->throwTypeError();
+ return Encode(false);
+ }
+
+ while (v) {
+ v = v->prototype();
+
+ if (! v)
+ break;
+ else if (o.getPointer() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
}
QV4::ReturnedValue __qmljs_in(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
@@ -367,7 +389,7 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
if (typeHint == NUMBER_HINT)
qSwap(meth1, meth2);
- ExecutionContext *ctx = engine->current;
+ ExecutionContext *ctx = engine->currentContext();
Scope scope(ctx);
ScopedCallData callData(scope, 0);
callData->thisObject = object;
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 17a19b5201..21f45745cb 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -41,7 +41,7 @@
#ifndef QV4SCOPEDVALUE_P_H
#define QV4SCOPEDVALUE_P_H
-#include "qv4engine_p.h"
+#include "qv4context_p.h"
#include "qv4value_def_p.h"
QT_BEGIN_NAMESPACE
@@ -231,7 +231,7 @@ struct Scoped
Scoped(const Scope &scope, const Value &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->current, v);
+ ptr->val = value_convert<T>(scope.engine->currentContext(), v);
#ifndef QT_NO_DEBUG
++scope.size;
#endif
@@ -278,7 +278,7 @@ struct Scoped
Scoped(const Scope &scope, const ReturnedValue &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->current, QV4::Value::fromReturnedValue(v));
+ ptr->val = value_convert<T>(scope.engine->currentContext(), QV4::Value::fromReturnedValue(v));
#ifndef QT_NO_DEBUG
++scope.size;
#endif
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index c65f1baf2b..4fd0569627 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -67,7 +67,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
{
Q_ASSERT(scope->inUse);
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
function = f;
function->compilationUnit->ref();
needsActivation = function->needsActivation();
@@ -77,7 +77,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->current->newQmlContext(this, qml);
+ qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
scope->engine->popContext();
}
@@ -88,7 +88,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
{
Q_ASSERT(scope->inUse);
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
function = 0;
needsActivation = false;
@@ -97,7 +97,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->current->newQmlContext(this, qml);
+ qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
scope->engine->popContext();
}
@@ -140,7 +140,7 @@ struct CompilationUnitHolder : public QV4::Object
, unit(unit)
{
unit->ref();
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~CompilationUnitHolder()
{
@@ -242,7 +242,7 @@ void Script::parse()
if (!vmFunction) {
// ### FIX file/line number
Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
}
}
@@ -377,7 +377,7 @@ QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &scr
QV4::Scope scope(engine);
QV4::Script qmlScript(engine, scopeObject, script, QString());
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
qmlScript.parse();
QV4::ScopedValue result(scope);
if (!scope.engine->hasException)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 26e4dcb8a2..8b0e31cb71 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -47,6 +47,7 @@
#include <private/qv4arrayobject_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4internalclass_p.h>
#include <algorithm>
@@ -167,14 +168,13 @@ class QQmlSequence : public QV4::Object
Q_MANAGED
public:
QQmlSequence(QV4::ExecutionEngine *engine, const Container &container)
- : QV4::Object(engine->sequenceClass)
+ : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject()))
, m_container(container)
, m_object(0)
, m_propertyIndex(-1)
, m_isReference(false)
{
type = Type_QmlSequence;
- vtbl = &static_vtbl;
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
@@ -183,13 +183,12 @@ public:
}
QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex)
- : QV4::Object(engine->sequenceClass)
+ : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject()))
, m_object(object)
, m_propertyIndex(propertyIndex)
, m_isReference(true)
{
type = Type_QmlSequence;
- vtbl = &static_vtbl;
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
@@ -207,7 +206,7 @@ public:
{
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed get"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed get"));
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
@@ -238,7 +237,7 @@ public:
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed set"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed set"));
return;
}
@@ -276,7 +275,7 @@ public:
{
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed query"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed query"));
return QV4::Attr_Invalid;
}
if (m_isReference) {
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 06a2603280..ee325db4c2 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -279,7 +279,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
s = properties->getIndexed(ii);
serialize(data, s, engine);
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
str = s;
val = o->get(str);
if (scope.hasException())
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 0e43d03987..e5633eb06f 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -108,7 +108,6 @@ const ManagedVTable String::static_vtbl =
markObjects,
destroy,
0 /*collectDeletables*/,
- hasInstance,
get,
getIndexed,
put,
@@ -150,7 +149,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
return Primitive::fromInt32(that->_text->size).asReturnedValue();
}
PropertyAttributes attrs;
- Property *pd = v4->stringClass->prototype->__getPropertyDescriptor__(name, &attrs);
+ Property *pd = v4->stringObjectClass->prototype->__getPropertyDescriptor__(name, &attrs);
if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
@@ -158,7 +157,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
}
if (hasProperty)
*hasProperty = true;
- return v4->stringClass->prototype->getValue(that, pd, attrs);
+ return v4->stringObjectClass->prototype->getValue(that, pd, attrs);
}
ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
@@ -173,7 +172,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
return Encode(engine->newString(that->toQString().mid(index, 1)));
}
PropertyAttributes attrs;
- Property *pd = engine->stringClass->prototype->__getPropertyDescriptor__(index, &attrs);
+ Property *pd = engine->stringObjectClass->prototype->__getPropertyDescriptor__(index, &attrs);
if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
@@ -181,7 +180,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
}
if (hasProperty)
*hasProperty = true;
- return engine->stringClass->prototype->getValue(that, pd, attrs);
+ return engine->stringObjectClass->prototype->getValue(that, pd, attrs);
}
void String::put(Managed *m, const StringRef name, const ValueRef value)
@@ -252,24 +251,22 @@ bool String::isEqualTo(Managed *t, Managed *o)
String::String(ExecutionEngine *engine, const QString &text)
- : Managed(engine ? engine->emptyClass : 0), _text(const_cast<QString &>(text).data_ptr())
+ : Managed(engine->stringClass), _text(const_cast<QString &>(text).data_ptr())
, identifier(0), stringHash(UINT_MAX)
, largestSubLength(0)
{
_text->ref.ref();
len = _text->size;
- vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
}
String::String(ExecutionEngine *engine, String *l, String *r)
- : Managed(engine ? engine->emptyClass : 0)
+ : Managed(engine->stringClass)
, left(l), right(r)
, stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength))
, len(l->len + r->len)
{
- vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
@@ -360,7 +357,7 @@ void String::createHashValue() const
// array indices get their number as hash value
bool ok;
- stringHash = toArrayIndex(ch, end, &ok);
+ stringHash = ::toArrayIndex(ch, end, &ok);
if (ok) {
subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex;
return;
@@ -382,7 +379,7 @@ uint String::createHashValue(const QChar *ch, int length)
// array indices get their number as hash value
bool ok;
- uint stringHash = toArrayIndex(ch, end, &ok);
+ uint stringHash = ::toArrayIndex(ch, end, &ok);
if (ok)
return stringHash;
@@ -401,7 +398,7 @@ uint String::createHashValue(const char *ch, int length)
// array indices get their number as hash value
bool ok;
- uint stringHash = toArrayIndex(ch, end, &ok);
+ uint stringHash = ::toArrayIndex(ch, end, &ok);
if (ok)
return stringHash;
@@ -415,3 +412,9 @@ uint String::createHashValue(const char *ch, int length)
return h;
}
+
+uint String::toArrayIndex(const QString &str)
+{
+ bool ok;
+ return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok);
+}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index bb6f1d2279..64e15b04c2 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -63,7 +63,7 @@ struct Q_QML_EXPORT String : public Managed {
String()
: Managed(0), _text(QStringData::sharedNull()), identifier(0)
, stringHash(UINT_MAX), largestSubLength(0), len(0)
- { vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; }
+ { type = Type_String; subtype = StringType_Unknown; }
String(ExecutionEngine *engine, const QString &text);
String(ExecutionEngine *engine, String *l, String *n);
~String() {
@@ -140,6 +140,8 @@ struct Q_QML_EXPORT String : public Managed {
return len;
}
+ static uint toArrayIndex(const QString &str);
+
union {
mutable QStringData *_text;
mutable String *left;
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index bff8f1f9cd..d468fb6b83 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -80,7 +80,7 @@ DEFINE_MANAGED_VTABLE(StringObject);
StringObject::StringObject(InternalClass *ic)
: Object(ic)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_StringObject;
Scope scope(engine());
@@ -94,9 +94,9 @@ StringObject::StringObject(InternalClass *ic)
}
StringObject::StringObject(ExecutionEngine *engine, const ValueRef val)
- : Object(engine->stringClass)
+ : Object(engine->stringObjectClass)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_StringObject;
Scope scope(engine);
@@ -125,13 +125,13 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index)
Scope scope(v4);
Scoped<StringObject> o(scope, m->asStringObject());
if (!o) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return false;
}
if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) {
- if (v4->current->strictMode)
- v4->current->throwTypeError();
+ if (v4->currentContext()->strictMode)
+ v4->currentContext()->throwTypeError();
return false;
}
return true;
@@ -172,7 +172,7 @@ DEFINE_MANAGED_VTABLE(StringCtor);
StringCtor::StringCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("String"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue StringCtor::construct(Managed *m, CallData *callData)
@@ -181,7 +181,7 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData)
Scope scope(v4);
ScopedValue value(scope);
if (callData->argc)
- value = callData->args[0].toString(v4->current);
+ value = callData->args[0].toString(v4->currentContext());
else
value = v4->newString(QString());
return Encode(v4->newStringObject(value));
@@ -193,7 +193,7 @@ ReturnedValue StringCtor::call(Managed *m, CallData *callData)
Scope scope(v4);
ScopedValue value(scope);
if (callData->argc)
- value = callData->args[0].toString(v4->current);
+ value = callData->args[0].toString(v4->currentContext());
else
value = v4->newString(QString());
return value.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 4ae570c8dc..30f7e8cdb0 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -90,7 +90,7 @@ double Value::toNumberImpl() const
if (isString())
return __qmljs_string_to_number(stringValue()->toQString());
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), NUMBER_HINT));
return prim->toNumber();
@@ -121,7 +121,7 @@ QString Value::toQStringNoThrow() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue ex(scope);
bool caughtException = false;
@@ -174,7 +174,7 @@ QString Value::toQString() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT));
return prim->toQString();
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 470e8e206b..dfa4ac5775 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -56,7 +56,6 @@ VariantObject::VariantObject(InternalClass *ic)
, ExecutionEngine::ScarceResourceData(QVariant())
, m_vmePropertyReferenceCount(0)
{
- vtbl = &static_vtbl;
}
VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
@@ -64,7 +63,6 @@ VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
, ExecutionEngine::ScarceResourceData(value)
, m_vmePropertyReferenceCount(0)
{
- vtbl = &static_vtbl;
if (isScarce())
engine->scarceResources.insert(this);
}
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 08bda0bce7..b0ea93e9fb 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -5,6 +5,7 @@ DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
+win32:!wince*:!winrt:LIBS += -lshell32
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
MODULE_PLUGIN_TYPES = \
@@ -17,6 +18,9 @@ exists("qqml_enable_gcov") {
QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
+# 2415: variable "xx" of static storage duration was declared but never referenced
+intel_icc: WERROR += -ww2415
+
load(qt_module)
HEADERS += qtqmlglobal.h \
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 321e6ccb41..012412b6b5 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -195,20 +195,6 @@ bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
return true;
}
-// Unicode stuff
-static inline bool isUnicodeNonCharacter(uint ucs4)
-{
- // Unicode has a couple of "non-characters" that one can use internally,
- // but are not allowed to be used for text interchange.
- //
- // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
- // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
- // U+FDEF (inclusive)
-
- return (ucs4 & 0xfffe) == 0xfffe
- || (ucs4 - 0xfdd0U) < 16;
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index f969f5c644..3bba6f8e83 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -126,7 +126,7 @@ HEADERS += \
$$PWD/qqmlplatform_p.h \
$$PWD/qqmlbinding_p.h \
$$PWD/qqmlextensionplugin_p.h \
- $$PWD/qqmlabstracturlinterceptor_p.h \
+ $$PWD/qqmlabstracturlinterceptor.h \
$$PWD/qqmlapplicationengine_p.h \
$$PWD/qqmlapplicationengine.h \
$$PWD/qqmllistwrapper_p.h \
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index b6c6fe840d..641209d1f3 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -467,7 +467,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
-static const int CurrentSingletonTypeRegistrationVersion = 2;
+enum { QmlCurrentSingletonTypeRegistrationVersion = 2 };
template <typename T>
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
QObject *(*callback)(QQmlEngine *, QJSEngine *))
@@ -475,7 +475,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
QML_GETTYPENAMES
QQmlPrivate::RegisterSingletonType api = {
- CurrentSingletonTypeRegistrationVersion,
+ QmlCurrentSingletonTypeRegistrationVersion,
uri, versionMajor, versionMinor, typeName,
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp
index 321698ad8e..127dad86ce 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.cpp
+++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp
@@ -44,9 +44,6 @@
\inmodule QtQml
\brief allows you to control QML file loading.
- \note This class is not currently public API, due to the risk of being affected
- by planned engine changes in upcoming releases.
-
QQmlAbstractUrlInterceptor is an interface which can be used to alter URLs
before they are used by the QML engine. This is primarily useful for altering
file urls into other file urls, such as selecting different graphical assets
diff --git a/src/qml/qml/qqmlabstracturlinterceptor_p.h b/src/qml/qml/qqmlabstracturlinterceptor.h
index 471c837eed..4bcaa89b4a 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor_p.h
+++ b/src/qml/qml/qqmlabstracturlinterceptor.h
@@ -43,11 +43,11 @@
#define QQMLABSTRACTURLINTERCEPTOR_H
#include <QtCore/qurl.h>
-#include <private/qtqmlglobal_p.h>
+#include <QtQml/qtqmlglobal.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlAbstractUrlInterceptor
+class Q_QML_EXPORT QQmlAbstractUrlInterceptor
{
Q_FLAGS(InterceptionPoint)
public:
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 557267d808..9e2fb07066 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -50,6 +50,7 @@
#include <private/qqmltrace_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlcontextwrapper_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -85,7 +86,14 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- rv = new QQmlBinding(cdata->primitives.at(id), obj, ctxtdata, url, lineNumber, 0);
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QV4::Scope valueScope(v4);
+ QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(v4->v8Engine, ctxtdata, obj));
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject));
+ QV4::ExecutionContext *qmlContext = wrapper->context();
+ QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
+ QV4::ScopedValue function(valueScope, QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction));
+ rv = new QQmlBinding(function, obj, ctxtdata, url, lineNumber, 0);
}
typeData->release();
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 11dc873dd4..68160edf5e 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -89,8 +89,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function)
: QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
m_v8function(function),
- m_line(-1),
- m_column(-1),
+ m_line(USHRT_MAX),
+ m_column(USHRT_MAX),
m_target(target),
m_index(index),
m_expressionFunctionValid(true),
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 9fcef176ad..76bf24fe6b 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -45,6 +45,7 @@
#include "qqmlcomponent_p.h"
#include "qqmlcontext.h"
#include "qqmlcontext_p.h"
+#include "qqmlpropertymap.h"
#ifdef QML_THREADED_VME_INTERPRETER
#include "qqmlvme_p.h"
#endif
@@ -173,6 +174,27 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngi
}
}
+template <typename T>
+bool qtTypeInherits(const QMetaObject *mo) {
+ while (mo) {
+ if (mo == &T::staticMetaObject)
+ return true;
+ mo = mo->superClass();
+ }
+ return false;
+}
+
+void QQmlCompiledData::TypeReference::doDynamicTypeCheck()
+{
+ const QMetaObject *mo = 0;
+ if (typePropertyCache)
+ mo = typePropertyCache->firstCppMetaObject();
+ else if (type)
+ mo = type->metaObject();
+ else
+ mo = component->rootPropertyCache->firstCppMetaObject();
+ isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
+}
void QQmlCompiledData::dumpInstructions()
{
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 54fd002f7b..2e208f2f3b 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -61,8 +61,7 @@
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlbinding_p.h"
-#include "qqmlabstracturlinterceptor_p.h"
-#include "qqmlcodegenerator_p.h"
+#include "qqmlabstracturlinterceptor.h"
#include <QDebug>
#include <QPointF>
@@ -848,6 +847,8 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
}
}
+ ref.doDynamicTypeCheck();
+
out->types << ref;
}
@@ -859,6 +860,19 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
if (componentStats)
dumpStats();
Q_ASSERT(out->rootPropertyCache);
+
+ // Any QQmlPropertyMap instances for example need to have their property cache removed,
+ // because the class is too dynamic and allows adding properties at any point at run-time.
+ for (int i = 0; i < output->types.count(); ++i) {
+ QQmlCompiledData::TypeReference &tr = output->types[i];
+ if (!tr.typePropertyCache)
+ continue;
+
+ if (tr.isFullyDynamicType) {
+ tr.typePropertyCache->release();
+ tr.typePropertyCache = 0;
+ }
+ }
} else {
reset(out);
}
@@ -1227,6 +1241,7 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper)
// Setup the synthesized meta object if necessary
if (!obj->synthdata.isEmpty()) {
+ Q_ASSERT(!output->types.at(obj->type).isFullyDynamicType);
Instruction::StoreMetaObject meta;
meta.aliasData = output->indexForByteArray(obj->synthdata);
meta.propertyCache = output->propertyCaches.count();
@@ -2682,14 +2697,42 @@ const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
return qmltype->metaObject();
}
-int QQmlCompiler::bindingIdentifier(const Variant &value)
+int QQmlCompiler::bindingIdentifier(const QString &name, const Variant &value, const BindingContext &ctxt)
{
- return output->indexForString(value.asScript());
+ JSBindingReference *reference = pool->New<JSBindingReference>();
+ reference->expression = value;
+ reference->property = pool->New<Property>();
+ reference->property->setName(name);
+ reference->value = 0;
+ reference->bindingContext = ctxt;
+ reference->bindingContext.owner++;
+ // Unfortunately this is required for example for PropertyChanges where the bindings
+ // will be executed in the dynamic scope of the target, so we can't resolve any lookups
+ // at run-time.
+ reference->disableLookupAcceleration = true;
+
+ const int id = output->customParserBindings.count();
+ output->customParserBindings.append(0); // Filled in later.
+ reference->customParserBindingsIndex = id;
+
+ compileState->totalBindingsCount++;
+ compileState->bindings.prepend(reference);
+
+ return id;
}
// Ensures that the dynamic meta specification on obj is valid
bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
{
+ if (output->types[obj->type].isFullyDynamicType) {
+ if (!obj->dynamicProperties.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new properties."));
+ if (!obj->dynamicSignals.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new signals."));
+ if (!obj->dynamicSlots.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully Dynamic types cannot declare new functions."));
+ }
+
bool seenDefaultProperty = false;
// We use a coarse grain, 31 bit hash to check if there are duplicates.
@@ -3644,11 +3687,14 @@ bool QQmlCompiler::completeComponentBuild()
}
ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
- cd->functionsToCompile.append(node);
+ QtQml::CompiledFunctionOrExpression f;
+ f.node = node;
+ f.name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ f.disableAcceleratedLookups = binding.disableLookupAcceleration;
+ cd->functionsToCompile.append(f);
binding.compiledIndex = cd->functionsToCompile.count() - 1;
- cd->expressionNames.insert(binding.compiledIndex, binding.property->name().toString().prepend(QStringLiteral("expression for ")));
- if (componentStats)
+ if (componentStats && b->value)
componentStats->componentStat.scriptBindings.append(b->value->location);
}
@@ -3656,7 +3702,7 @@ bool QQmlCompiler::completeComponentBuild()
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- JSCodeGen jsCodeGen(enginePrivate, unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
+ JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
JSCodeGen::ObjectIdMapping idMapping;
if (compileState->ids.count() > 0) {
@@ -3679,7 +3725,7 @@ bool QQmlCompiler::completeComponentBuild()
jsCodeGen.beginObjectScope(scopeObject->metatype);
- cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile, cd->expressionNames);
+ cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile);
QList<QQmlError> errors = jsCodeGen.errors();
if (!errors.isEmpty()) {
exceptions << errors;
@@ -3697,6 +3743,10 @@ bool QQmlCompiler::completeComponentBuild()
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
JSBindingReference &binding = *b;
binding.compiledIndex = compileState->jsCompileData[binding.bindingContext.object].runtimeFunctionIndices[binding.compiledIndex];
+ if (!binding.value) { // Must be a binding requested from custom parser
+ Q_ASSERT(binding.customParserBindingsIndex >= 0 && binding.customParserBindingsIndex < output->customParserBindings.count());
+ output->customParserBindings[binding.customParserBindingsIndex] = binding.compiledIndex;
+ }
}
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 05c877d98b..516f6653ca 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -62,6 +62,7 @@
#include "qqmlpropertycache_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmltypeloader_p.h"
+#include <private/qqmlcodegenerator_p.h>
#include "private/qv4identifier_p.h"
#include <private/qqmljsastfwd_p.h>
@@ -105,6 +106,7 @@ public:
: type(0), typePropertyCache(0), component(0)
, majorVersion(0)
, minorVersion(0)
+ , isFullyDynamicType(false)
{}
QQmlType *type;
@@ -113,9 +115,14 @@ public:
int majorVersion;
int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
QQmlPropertyCache *propertyCache() const;
QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+
+ void doDynamicTypeCheck();
};
// --- old compiler:
QList<TypeReference> types;
@@ -150,6 +157,7 @@ public:
// index in first hash is component index, hash inside maps from object index in that scope to integer id
QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, int> objectIndexToIdForRoot;
+ QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
@@ -224,14 +232,15 @@ namespace QQmlCompilerTypes {
struct JSBindingReference : public QQmlPool::Class,
public BindingReference
{
- JSBindingReference() : nextReference(0) {}
+ JSBindingReference() : disableLookupAcceleration(false), nextReference(0) {}
QQmlScript::Variant expression;
QQmlScript::Property *property;
QQmlScript::Value *value;
int compiledIndex : 16;
- int sharedIndex : 16;
+ int customParserBindingsIndex : 15;
+ int disableLookupAcceleration: 1;
BindingContext bindingContext;
@@ -312,10 +321,9 @@ namespace QQmlCompilerTypes {
QList<CompiledMetaMethod> compiledMetaMethods;
struct PerObjectCompileData
{
- QList<QQmlJS::AST::Node*> functionsToCompile;
+ QList<QtQml::CompiledFunctionOrExpression> functionsToCompile;
QVector<int> runtimeFunctionIndices;
QVector<CompiledMetaMethod> compiledMetaMethods;
- QHash<int, QString> expressionNames;
};
QHash<QQmlScript::Object *, PerObjectCompileData> jsCompileData;
};
@@ -340,7 +348,7 @@ public:
int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const; // for QQmlCustomParser::evaluateEnum
const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
- int bindingIdentifier(const QQmlScript::Variant& value); // for QQmlCustomParser::bindingIndex
+ int bindingIdentifier(const QString &name, const QQmlScript::Variant& value, const QQmlCompilerTypes::BindingContext &ctxt); // for QQmlCustomParser::bindingIndex
private:
typedef QQmlCompiledData::Instruction Instruction;
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index ae246f5cd4..4a71c1a7e0 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1491,7 +1491,7 @@ QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::Incubat
{
incubator.reset(new QQmlComponentIncubator(this, m));
v8 = engine;
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
valuemap = QV4::Primitive::undefinedValue();
qmlGlobal = QV4::Primitive::undefinedValue();
@@ -1546,7 +1546,7 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QV4::ScopedFunctionObject f(scope, m_statusChanged);
if (f) {
- QV4::ExecutionContext *ctx = scope.engine->current;
+ QV4::ExecutionContext *ctx = scope.engine->currentContext();
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = this;
callData->args[0] = QV4::Primitive::fromUInt32(s);
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 7731935b75..78e6650d02 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -48,7 +48,7 @@
#include "qqmlengine_p.h"
#include "qqmlengine.h"
#include "qqmlinfo.h"
-#include "qqmlabstracturlinterceptor_p.h"
+#include "qqmlabstracturlinterceptor.h"
#include <qjsengine.h>
#include <QtCore/qvarlengtharray.h>
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 54b540bb4c..b3c2105e68 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -66,7 +66,7 @@ QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context
v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
context(context), scopeObject(scopeObject), idObjectsWrapper(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlContextWrapper::~QmlContextWrapper()
@@ -137,7 +137,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
QV4::Scope scope(v4);
QmlContextWrapper *resource = m->as<QmlContextWrapper>();
if (!resource)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
// In V8 the JS global object would come _before_ the QML global object,
// so simulate that here.
@@ -246,7 +246,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
// Search scope object
if (scopeObject) {
bool hasProp = false;
- QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->current, context, scopeObject,
+ QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, scopeObject,
name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp));
if (hasProp) {
if (hasProperty)
@@ -260,7 +260,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
// Search context object
if (context->contextObject) {
bool hasProp = false;
- result = QV4::QObjectWrapper::getQmlProperty(v4->current, context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp);
+ result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp);
if (hasProp) {
if (hasProperty)
*hasProperty = true;
@@ -284,7 +284,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
return;
QV4::Scoped<QmlContextWrapper> wrapper(scope, m->as<QmlContextWrapper>());
if (!wrapper) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -292,8 +292,8 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
if (wrapper && wrapper->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
- Scoped<String> e(scope, v4->current->engine->newString(error));
- v4->current->throwError(e);
+ Scoped<String> e(scope, v4->currentContext()->engine->newString(error));
+ v4->currentContext()->throwError(e);
return;
}
@@ -327,13 +327,13 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
// Search scope object
if (scopeObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
return;
scopeObject = 0;
// Search context object
if (context->contextObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
return;
context = context->parent;
@@ -344,7 +344,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
if (wrapper->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
return;
}
@@ -439,7 +439,7 @@ QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrappe
: Object(engine)
, contextWrapper(contextWrapper)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty)
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index eba2e14e51..19e49009ce 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -313,8 +313,7 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
*/
QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Variant &value, const QString& name)
{
- Q_UNUSED(name);
- return compiler->bindingIdentifier(value);
+ return compiler->bindingIdentifier(name, value, QQmlCompilerTypes::BindingContext(object));
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 1f45cba732..f8e5ad5874 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -66,7 +66,7 @@
#include <private/qv4debugservice_p.h>
#include <private/qdebugmessageservice_p.h>
#include "qqmlincubator.h"
-#include "qqmlabstracturlinterceptor_p.h"
+#include "qqmlabstracturlinterceptor.h"
#include <private/qv8profilerservice_p.h>
#include <private/qqmlboundsignal_p.h>
@@ -101,6 +101,9 @@
#ifdef Q_OS_WIN // for %APPDATA%
#include <qt_windows.h>
+# if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+# include <shlobj.h>
+# endif
#include <qlibrary.h>
#include <windows.h>
@@ -2285,6 +2288,28 @@ bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
return typeLoader.isScriptLoaded(url);
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+// Normalize a file name using Shell API. As opposed to converting it
+// to a short 8.3 name and back, this also works for drives where 8.3 notation
+// is disabled (see 8dot3name options of fsutil.exe).
+static inline QString shellNormalizeFileName(const QString &name)
+{
+ const QString nativeSeparatorName(QDir::toNativeSeparators(name));
+ const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
+ PIDLIST_ABSOLUTE file;
+ if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
+ return name;
+ TCHAR buffer[MAX_PATH];
+ if (!SHGetPathFromIDList(file, buffer))
+ return name;
+ QString canonicalName = QString::fromWCharArray(buffer);
+ // Upper case drive letter
+ if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
+ canonicalName[0] = canonicalName.at(0).toUpper();
+ return QDir::cleanPath(canonicalName);
+}
+#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
+
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
@@ -2294,14 +2319,7 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
const QString canonical = info.canonicalFilePath();
#elif defined(Q_OS_WIN)
- wchar_t buffer[1024];
-
- DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
- if (rv == 0 || rv >= 1024) return true;
- rv = ::GetLongPathName(buffer, buffer, 1024);
- if (rv == 0 || rv >= 1024) return true;
-
- const QString canonical = QString::fromWCharArray(buffer);
+ const QString canonical = shellNormalizeFileName(absolute);
#endif
const int absoluteLength = absolute.length();
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 7f2007ec00..6ddc2eb2ff 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -40,10 +40,10 @@
****************************************************************************/
#include <QtCore/QFileSelector>
+#include <QtQml/QQmlAbstractUrlInterceptor>
#include <qobjectdefs.h>
#include "qqmlfileselector.h"
#include "qqmlfileselector_p.h"
-#include "qqmlabstracturlinterceptor_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index fe3679e08d..501f563ade 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -54,8 +54,8 @@
//
#include "qqmlfileselector.h"
-#include "qqmlabstracturlinterceptor_p.h"
#include <QSet>
+#include <QQmlAbstractUrlInterceptor>
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 30b5abb383..8645d2116a 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1966,8 +1966,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- const char *moduleId = uri.toUtf8().constData();
- ep->typeLoader.initializeEngine(eiface, moduleId);
+ ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData());
}
}
}
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 3fd0003656..499ade1ca5 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -155,7 +155,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
callData->thisObject = v4->globalObject;
if (scopeObject()) {
QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()));
@@ -294,7 +294,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scopeObject));
@@ -328,7 +328,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope));
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 73dc3192aa..7b975c2cc8 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -56,7 +56,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine)
: Object(QV8Engine::getV4(engine)),
v8(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
@@ -106,7 +106,7 @@ ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasPro
QV4::ExecutionEngine *v4 = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (name->equals(v4->id_length) && !w->object.isNull()) {
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
@@ -127,7 +127,7 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper
QV4::ExecutionEngine *e = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- return e->current->throwTypeError();
+ return e->currentContext()->throwTypeError();
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
if (index < count && w->property.at)
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 5e8130f407..36e0da5b60 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -61,7 +61,7 @@ public:
QQmlLocaleData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_Object;
}
@@ -872,7 +872,7 @@ QV4::ReturnedValue QQmlLocale::locale(QV8Engine *v8engine, const QString &locale
void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
{
- engine->stringClass->prototype->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
+ engine->stringObjectClass->prototype->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
}
QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp
index e7b6653532..d93276fc17 100644
--- a/src/qml/qml/qqmlmemoryprofiler.cpp
+++ b/src/qml/qml/qqmlmemoryprofiler.cpp
@@ -100,8 +100,7 @@ static bool openLibrary()
QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) : pushed(false)
{
if (openLibrary() && memprofile_is_enabled()) {
- const char *location = url.path().toUtf8().constData();
- memprofile_push_location(location, 0);
+ memprofile_push_location(url.path().toUtf8().constData(), 0);
pushed = true;
}
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 911761d9fd..6eda55e35b 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "qqmltypeloader_p.h"
-#include "qqmlabstracturlinterceptor_p.h"
+#include "qqmlabstracturlinterceptor.h"
#include "qqmlcontextwrapper_p.h"
#include "qqmlexpression_p.h"
@@ -2371,9 +2371,8 @@ void QQmlTypeData::compile()
// Compile JS binding expressions and signal handlers
- JSCodeGen jsCodeGen(enginePrivate, finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
- QHash<int, QString> expressionNames; // ### TODO
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions, expressionNames);
+ JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
@@ -2806,7 +2805,7 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
QV4::ScopedValue qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v8engine, ctxt, 0));
QV4::QmlContextWrapper::takeContextOwnership(qmlglobal);
- QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->current;
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->currentContext();
m_program->qml = qmlglobal;
m_program->run();
if (scope.engine->hasException) {
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c9a5edc39e..b93cf2942d 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -59,6 +59,7 @@
#include <QtQml/qqmlerror.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlfile.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlscript_p.h>
@@ -67,7 +68,6 @@
#include <private/qqmldirparser_p.h>
#include <private/qqmlbundle_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qqmlabstracturlinterceptor_p.h>
#include <private/qv4value_p.h>
#include <private/qv4script_p.h>
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 258442bc1d..9c350a54a5 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -60,7 +60,7 @@ QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine)
: Object(QV8Engine::getV4(engine)),
v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlTypeWrapper::~QmlTypeWrapper()
@@ -126,7 +126,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
Scoped<QmlTypeWrapper> w(scope, m->as<QmlTypeWrapper>());
if (!w)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (hasProperty)
@@ -165,7 +165,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
}
// check for property.
- return QV4::QObjectWrapper::getQmlProperty(v4->current, context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
} 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::get(siinfo->scriptApi(e))->getValue(v4));
@@ -188,7 +188,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
} else if (w->object) {
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- return QV4::QObjectWrapper::getQmlProperty(v4->current, context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
// Fall through to base implementation
}
@@ -236,7 +236,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
if (v4->hasException)
return;
if (!w) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -249,7 +249,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObject *object = w->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
} else if (type && type->isSingleton()) {
QQmlEngine *e = v8engine->engine();
QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
@@ -257,12 +257,12 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
} else if (!siinfo->scriptApi(e).isUndefined()) {
QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value);
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
return;
} else {
apiprivate->put(name, value);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index d733694923..50d7cbcc5e 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -79,7 +79,7 @@ QmlValueTypeWrapper::QmlValueTypeWrapper(QV8Engine *engine, ObjectType objectTyp
: Object(QV8Engine::getV4(engine)), objectType(objectType)
{
v8 = engine;
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlValueTypeWrapper::~QmlValueTypeWrapper()
@@ -209,7 +209,7 @@ PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name)
const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return PropertyAttributes();
}
@@ -273,7 +273,7 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
// Note: readReferenceValue() can change the reference->type.
if (r->objectType == QmlValueTypeWrapper::Reference) {
@@ -306,7 +306,7 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
if (result->isFunction()) {
// calling a Q_INVOKABLE function of a value type
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return QV4::QObjectWrapper::getQmlProperty(v4->current, qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
@@ -339,7 +339,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
Scoped<QmlValueTypeWrapper> r(scope, m->as<QmlValueTypeWrapper>());
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -365,7 +365,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
// assigning a JS function to a non-var-property is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
Scoped<String> e(scope, r->v8->toString(error));
- v4->current->throwError(e);
+ v4->currentContext()->throwError(e);
return;
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 4b34792421..ebe72b2ff6 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -956,7 +956,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
QV4::ScopedValue result(scope);
- QV4::ExecutionContext *ctx = function->engine()->current;
+ QV4::ExecutionContext *ctx = function->engine()->currentContext();
result = function->call(callData);
if (scope.hasException()) {
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 18e3e33c4b..ad231d0769 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -192,7 +192,7 @@ public:
, list(list)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -226,7 +226,7 @@ public:
: Object(engine)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -258,7 +258,7 @@ public:
NodePrototype(ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedObject protectThis(scope, this);
@@ -312,7 +312,7 @@ class Node : public Object
: Object(engine)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -906,7 +906,7 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty
QV4::ExecutionEngine *v4 = m->engine();
NamedNodeMap *r = m->as<NamedNodeMap>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -925,7 +925,7 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope
NamedNodeMap *r = m->as<NamedNodeMap>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
name->makeIdentifier();
if (name->equals(v4->id_length))
@@ -961,7 +961,7 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -980,7 +980,7 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
name->makeIdentifier();
@@ -1535,7 +1535,7 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
{
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
Scoped<Object> o(scope, me);
if (!o) {
@@ -1560,7 +1560,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
s = v4->newString(QStringLiteral("ActivationObject"));
Scoped<Object> activationObject(scope, o->get(s));
if (!activationObject) {
- v4->current->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
+ v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
return;
}
@@ -1580,7 +1580,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me)
{
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
dispatchCallbackImpl(me);
if (v4->hasException) {
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
@@ -1605,7 +1605,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
: Object(engine)
, request(request)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~QQmlXMLHttpRequestWrapper() {
delete request;
@@ -1626,7 +1626,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
QQmlXMLHttpRequestCtor(ExecutionEngine *engine)
: FunctionObject(engine->rootContext, QStringLiteral("XMLHttpRequest"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedValue protectThis(scope, this);
@@ -1656,7 +1656,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(that->engine());
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
if (!ctor)
- return that->engine()->current->throwTypeError();
+ return that->engine()->currentContext()->throwTypeError();
QV8Engine *engine = that->engine()->v8Engine;
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index c80a742af0..41d5de0862 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -90,7 +90,7 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
, m_platform(0)
, m_application(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(v4);
ScopedObject protectThis(scope, this);
@@ -1183,7 +1183,7 @@ struct BindingFunction : public QV4::FunctionObject
: QV4::FunctionObject(originalFunction->scope, originalFunction->name)
, originalFunction(originalFunction)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
bindingKeyFlag = true;
}
@@ -1608,7 +1608,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
// string prototype extension
- v4->stringClass->prototype->defineDefaultProperty(QStringLiteral("arg"), method_string_arg);
+ v4->stringObjectClass->prototype->defineDefaultProperty(QStringLiteral("arg"), method_string_arg);
}
@@ -1726,7 +1726,9 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
QString path = ctxt->url.toString();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : QString();
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
QString text = ctx->callData->args[0].toQStringNoThrow();
QString comment;
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index d0fc1b1295..33f5a00a6c 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -95,7 +95,7 @@ QV8Engine::QV8Engine(QJSEngine* qq)
, m_listModelData(0)
{
#ifdef Q_PROCESSOR_X86_32
- if (!(qCpuFeatures() & SSE2)) {
+ if (!qCpuHasFeature(SSE2)) {
qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer");
}
#endif
@@ -256,7 +256,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(ptr));
case QMetaType::QString:
- return m_v4Engine->current->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
+ return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(ptr));
case QMetaType::Short:
@@ -667,7 +667,7 @@ QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(data));
case QMetaType::QString:
- return m_v4Engine->current->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
+ return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(data));
case QMetaType::Short:
@@ -750,7 +750,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
if (value->isUndefined() || value->isNull())
*reinterpret_cast<QString*>(data) = QString();
else
- *reinterpret_cast<QString*>(data) = value->toString(m_v4Engine->current)->toQString();
+ *reinterpret_cast<QString*>(data) = value->toString(m_v4Engine->currentContext())->toQString();
return true;
case QMetaType::Float:
*reinterpret_cast<float*>(data) = value->toNumber();
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 754d008745..7276c0e5c6 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -71,12 +71,12 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
, code(code)
, flag(flag)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData)
@@ -86,7 +86,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
QV4::Scoped<DelegateModelGroupFunction> f(scope, that, QV4::Scoped<DelegateModelGroupFunction>::Cast);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject);
if (!o)
- return v4->current->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QV4::ScopedValue v(scope, callData->argument(0));
return f->code(o->item, f->flag, v);
@@ -3144,7 +3144,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object
QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
@@ -3183,7 +3183,7 @@ public:
QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
virtual ~QQmlDelegateModelGroupChangeArray() {}
@@ -3197,7 +3197,7 @@ public:
QV4::Scope scope(v4);
QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, m->as<QQmlDelegateModelGroupChangeArray>());
if (!array)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (index >= array->count()) {
if (hasProperty)
@@ -3221,7 +3221,7 @@ public:
{
QQmlDelegateModelGroupChangeArray *array = m->as<QQmlDelegateModelGroupChangeArray>();
if (!array)
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
if (name->equals(m->engine()->id_length)) {
if (hasProperty)
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 066c8e70e5..f78cf38535 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -165,7 +165,7 @@ struct QQmlDelegateModelItemObject : QV4::Object
QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item)
: Object(engine)
, item(item)
- { vtbl = &static_vtbl; }
+ { setVTable(&static_vtbl); }
~QQmlDelegateModelItemObject();
static void destroy(Managed *that);
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
index 1fed95eb85..f44be9d4b4 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qml/types/qquickpackage.cpp
@@ -65,15 +65,15 @@ QT_BEGIN_NAMESPACE
delegate it should appear in. This allows an item to move
between views.
- \snippet quick/views/package/Delegate.qml 0
+ \snippet package/Delegate.qml 0
These named items are used as the delegates by the two views who
reference the special \l{VisualDataModel::parts} property to select
a model which provides the chosen delegate.
- \snippet quick/views/package/view.qml 0
+ \snippet package/view.qml 0
- \sa {quick/views/package}{Package example}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
+ \sa {Qt Quick Examples - Views}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
*/
/*!
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 7607febe01..53e45e2003 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -252,7 +252,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, createsend.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedValue v(scope);
QV4::ScopedCallData callData(scope, 1);
@@ -356,7 +356,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
QV4::ExecutionEngine *v4 = QV8Engine::getV4(workerEngine);
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, workerEngine->onmessage.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, workerEngine));
@@ -398,7 +398,7 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
QV4::Script program(v4, activation, sourceCode, url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
program.parse();
if (!v4->hasException)
program.run();
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 559f41e546..2d8fbb5f85 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -71,8 +71,6 @@ public:
virtual void setV8Engine(QV8Engine *engine) = 0;
virtual QV4::ReturnedValue v4value() const = 0;
- virtual QSGDynamicTexture *texture() const = 0;
-
virtual QImage toImage(const QRectF& bounds) = 0;
Q_SIGNALS:
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index ee1b5f316c..be9c592228 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -44,8 +44,10 @@
#include <private/qquickitem_p.h>
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
+#include <private/qquickcontext2dtexture_p.h>
#include <qsgsimpletexturenode.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtGui/QGuiApplication>
#include <qqmlinfo.h>
#include <private/qqmlengine_p.h>
@@ -58,19 +60,15 @@
QT_BEGIN_NAMESPACE
-QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image)
: m_pixmap(0)
, m_image(image)
- , m_texture(0)
- , m_window(window)
{
}
-QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap)
: m_pixmap(pixmap)
- , m_texture(0)
- , m_window(window)
{
}
@@ -78,8 +76,6 @@ QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *windo
QQuickCanvasPixmap::~QQuickCanvasPixmap()
{
delete m_pixmap;
- if (m_texture)
- m_texture->deleteLater();
}
qreal QQuickCanvasPixmap::width() const
@@ -105,18 +101,6 @@ bool QQuickCanvasPixmap::isValid() const
return !m_image.isNull();
}
-QSGTexture *QQuickCanvasPixmap::texture()
-{
- if (!m_texture) {
- if (m_pixmap) {
- Q_ASSERT(m_pixmap->textureFactory());
- m_texture = m_pixmap->textureFactory()->createTexture(m_window);
- } else {
- m_texture = m_window->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas);
- }
- }
- return m_texture;
-}
QImage QQuickCanvasPixmap::image()
{
if (m_image.isNull() && m_pixmap)
@@ -194,7 +178,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasCanvasWindow(false)
, available(false)
, renderTarget(QQuickCanvasItem::Image)
- , renderStrategy(QQuickCanvasItem::Cooperative)
+ , renderStrategy(QQuickCanvasItem::Immediate)
{
implicitAntialiasing = true;
}
@@ -246,10 +230,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
- results in faster rendering.
+ results in faster rendering. Canvas.FramebufferObject relies on the
+ OpenGL extensions \c GL_EXT_framebuffer_multisample and
+ \c GL_EXT_framebuffer_blit for antialiasing. It will also use more
+ graphics memory when rendering strategy is anything other than
+ Canvas.Cooperative.
The default render target is Canvas.Image and the default renderStrategy is
- Canvas.Cooperative.
+ Canvas.Immediate.
\section1 Tiled Canvas
The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
@@ -489,7 +477,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
context will choose appropriate options and Canvas will signal the change
to the properties.
- The default render target is \c Canvas.FramebufferObject.
+ The default render target is \c Canvas.Image.
*/
QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
{
@@ -531,7 +519,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
rendering will occur on a thread separate from the GUI thread.
- The default value is \c Canvas.Cooperative.
+ The default value is \c Canvas.Immediate.
\sa renderTarget
*/
@@ -689,6 +677,15 @@ void QQuickCanvasItem::updatePolish()
}
}
+class QQuickCanvasNode : public QSGSimpleTextureNode
+{
+public:
+ ~QQuickCanvasNode()
+ {
+ delete texture();
+ }
+};
+
QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickCanvasItem);
@@ -698,9 +695,9 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
+ QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
if (!node)
- node = new QSGSimpleTextureNode;
+ node = new QQuickCanvasNode();
if (d->smooth)
node->setFiltering(QSGTexture::Linear);
@@ -712,8 +709,15 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
d->context->flush();
}
- node->setTexture(d->context->texture());
- node->markDirty(QSGNode::DirtyMaterial);
+ QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
+ QQuickContext2DTexture *factory = ctx->texture();
+ QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ if (!texture) {
+ delete node;
+ return 0;
+ }
+
+ node->setTexture(texture);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -916,7 +920,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url)
if (!d->pixmaps.contains(fullPathUrl)) {
QQuickPixmap* pix = new QQuickPixmap();
QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
- canvasPix.take(new QQuickCanvasPixmap(pix, d->window));
+ canvasPix.take(new QQuickCanvasPixmap(pix));
d->pixmaps.insert(fullPathUrl, canvasPix);
pix->load(qmlEngine(this)
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 2ec36cfe73..3baf68d418 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -52,17 +52,15 @@ QT_BEGIN_NAMESPACE
class QQuickCanvasContext;
class QQuickCanvasItemPrivate;
-class QSGTexture;
class QQuickPixmap;
class QQuickCanvasPixmap : public QQmlRefCount
{
public:
- QQuickCanvasPixmap(const QImage& image, QQuickWindow *window);
- QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window);
+ QQuickCanvasPixmap(const QImage& image);
+ QQuickCanvasPixmap(QQuickPixmap *pixmap);
~QQuickCanvasPixmap();
- QSGTexture *texture();
QImage image();
qreal width() const;
@@ -73,8 +71,6 @@ public:
private:
QQuickPixmap *m_pixmap;
QImage m_image;
- QSGTexture *m_texture;
- QQuickWindow *m_window;
};
class QQuickCanvasItem : public QQuickItem
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2a9e0f2ac2..b6eb2db33d 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -484,7 +484,7 @@ public:
QQuickJSContext2D(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QQuickContext2D* context;
@@ -653,7 +653,7 @@ public:
, patternRepeatX(false)
, patternRepeatY(false)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QBrush brush;
bool patternRepeatX:1;
@@ -870,7 +870,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
QQuickJSContext2DPixelData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
@@ -893,7 +893,7 @@ struct QQuickJSContext2DImageData : public QV4::Object
QQuickJSContext2DImageData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
pixelData = QV4::Primitive::undefinedValue();
QV4::Scope scope(engine);
@@ -2985,14 +2985,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
- pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
+ pixmap.take(new QQuickCanvasPixmap(img));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else if (QV4::Referenced<QQuickJSContext2DImageData> imageData = arg->asRef<QQuickJSContext2DImageData>()) {
QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
if (pix && !pix->image.isNull()) {
- pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
+ pixmap.take(new QQuickCanvasPixmap(pix->image));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
@@ -3165,7 +3165,7 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!m)
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
if (hasProperty)
@@ -3200,7 +3200,7 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -4084,6 +4084,15 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
QQuickWindow *window = canvasItem->window();
m_renderStrategy = canvasItem->renderStrategy();
+#ifdef Q_OS_WIN
+ if (m_renderTarget == QQuickCanvasItem::FramebufferObject
+ && (m_renderStrategy != QQuickCanvasItem::Cooperative)) {
+ // On windows a context needs to be unbound set up sharing, so
+ // for simplicity we disallow FBO + !coop here.
+ m_renderTarget = QQuickCanvasItem::Image;
+ }
+#endif
+
switch (m_renderTarget) {
case QQuickCanvasItem::Image:
m_texture = new QQuickContext2DImageTexture;
@@ -4099,6 +4108,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
m_texture->setSmooth(canvasItem->smooth());
m_texture->setAntialiasing(canvasItem->antialiasing());
+ m_texture->setOnCustomThread(m_renderStrategy == QQuickCanvasItem::Threaded);
m_thread = QThread::currentThread();
QThread *renderThread = m_thread;
@@ -4129,28 +4139,31 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing)
{
- QMetaObject::invokeMethod(m_texture
- , "canvasChanged"
- , Qt::AutoConnection
- , Q_ARG(QSize, canvasSize)
- , Q_ARG(QSize, tileSize)
- , Q_ARG(QRect, canvasWindow)
- , Q_ARG(QRect, dirtyRect)
- , Q_ARG(bool, smooth)
- , Q_ARG(bool, antialiasing));
+ if (m_texture->thread() == QThread::currentThread()) {
+ m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth, antialiasing);
+ } else {
+ QEvent *e = new QQuickContext2DTexture::CanvasChangeEvent(canvasSize,
+ tileSize,
+ canvasWindow,
+ dirtyRect,
+ smooth,
+ antialiasing);
+ QCoreApplication::postEvent(m_texture, e);
+ }
}
void QQuickContext2D::flush()
{
- if (m_buffer)
- QMetaObject::invokeMethod(m_texture,
- "paint",
- Qt::AutoConnection,
- Q_ARG(QQuickContext2DCommandBuffer*, m_buffer));
+ if (m_buffer) {
+ if (m_texture->thread() == QThread::currentThread())
+ m_texture->paint(m_buffer);
+ else
+ QCoreApplication::postEvent(m_texture, new QQuickContext2DTexture::PaintEvent(m_buffer));
+ }
m_buffer = new QQuickContext2DCommandBuffer();
}
-QSGDynamicTexture *QQuickContext2D::texture() const
+QQuickContext2DTexture *QQuickContext2D::texture() const
{
return m_texture;
}
@@ -4164,6 +4177,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
return QImage();
} else {
+ QCoreApplication::postEvent(m_texture, new QEvent(QEvent::Type(QEvent::User + 10)));
QMetaObject::invokeMethod(m_texture,
"grabImage",
Qt::BlockingQueuedConnection,
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 4bef50d9cd..6399da3dee 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -74,6 +74,8 @@ class QOpenGLContext;
class QQuickContext2D : public QQuickCanvasContext
{
+ Q_OBJECT
+
public:
Q_DISABLE_COPY(QQuickContext2D)
@@ -171,8 +173,8 @@ public:
void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void flush();
void sync();
- QThread *thread() const {return m_thread;}
- QSGDynamicTexture *texture() const;
+ QThread *thread() const { return m_thread; }
+ QQuickContext2DTexture *texture() const;
QImage toImage(const QRectF& bounds);
QV4::ReturnedValue v4value() const;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index d2f4e3317d..06a0713365 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -420,38 +420,8 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
Q_ASSERT(!pix.isNull());
const bool hasShadow = HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
- if (p->paintEngine()->type() != QPaintEngine::OpenGL2 || hasShadow){
- //TODO: generate shadow blur with shaders
- qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
- } else if (pix->texture()){
- QSGTexture *tex = pix->texture();
- QSGDynamicTexture *dynamicTexture = qobject_cast<QSGDynamicTexture *>(tex);
- if (dynamicTexture)
- dynamicTexture->updateTexture();
-
- if (tex->textureId()) {
-
- if (sr.width() < 0)
- sr.setWidth(tex->textureSize().width());
- if (sr.height() < 0)
- sr.setHeight(tex->textureSize().height());
-
- if (dr.width() < 0)
- dr.setWidth(sr.width());
- if (dr.height() < 0)
- dr.setHeight(sr.height());
-
- qreal srBottom = sr.bottom();
- sr.setBottom(sr.top());
- sr.setTop(srBottom);
-
- tex->bind();
- if (p->paintEngine()->type() == QPaintEngine::OpenGL2) {
- QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx *>(p->paintEngine());
- engine->drawTexture(dr, tex->textureId(), tex->textureSize(), sr);
- }
- }
- }
+ //TODO: generate shadow blur with shaders
+ qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
break;
}
case QQuickContext2D::GetImageData:
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 29cdc73708..9e79333a0c 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -58,8 +58,6 @@ public:
void reset();
void clear();
- void lockQueue() { queueLock.lock(); }
- void unlockQueue() { queueLock.unlock(); }
inline int size() {return commands.size();}
inline bool isEmpty() const {return commands.isEmpty(); }
inline bool hasNext() const {return cmdIdx < commands.size(); }
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 8dc9978089..8dd48b4988 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -50,6 +50,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QtCore/QThread>
+#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -90,7 +91,6 @@ struct GLAcquireContext {
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
, m_item(0)
- , m_dirtyCanvas(false)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
, m_smooth(true)
@@ -105,23 +105,20 @@ QQuickContext2DTexture::~QQuickContext2DTexture()
clearTiles();
}
-QSize QQuickContext2DTexture::textureSize() const
-{
- return m_canvasWindow.size();
-}
-
void QQuickContext2DTexture::markDirtyTexture()
{
+ if (m_onCustomThread)
+ m_mutex.lock();
m_dirtyTexture = true;
- updateTexture();
emit textureChanged();
+ if (m_onCustomThread)
+ m_mutex.unlock();
}
bool QQuickContext2DTexture::setCanvasSize(const QSize &size)
{
if (m_canvasSize != size) {
m_canvasSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -131,7 +128,6 @@ bool QQuickContext2DTexture::setTileSize(const QSize &size)
{
if (m_tileSize != size) {
m_tileSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -195,7 +191,6 @@ void QQuickContext2DTexture::canvasChanged(const QSize& canvasSize, const QSize&
if (canvasSize == canvasWindow.size()) {
m_tiledCanvas = false;
- m_dirtyCanvas = false;
} else {
m_tiledCanvas = true;
}
@@ -309,7 +304,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
m_tiles.clear();
if (window.isEmpty()) {
- m_dirtyCanvas = false;
return QRect();
}
@@ -351,7 +345,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
qDeleteAll(oldTiles);
- m_dirtyCanvas = false;
return r;
}
@@ -366,6 +359,20 @@ QSize QQuickContext2DTexture::adjustedTileSize(const QSize &ts)
return ts;
}
+bool QQuickContext2DTexture::event(QEvent *e)
+{
+ if ((int) e->type() == QEvent::User + 1) {
+ PaintEvent *pe = static_cast<PaintEvent *>(e);
+ paint(pe->buffer);
+ return true;
+ } else if ((int) e->type() == QEvent::User + 2) {
+ CanvasChangeEvent *ce = static_cast<CanvasChangeEvent *>(e);
+ canvasChanged(ce->canvasSize, ce->tileSize, ce->canvasWindow, ce->dirtyRect, ce->smooth, ce->antialiasing);
+ return true;
+ }
+ return QObject::event(e);
+}
+
static inline QSize npotAdjustedSize(const QSize &size)
{
static bool checked = false;
@@ -391,6 +398,9 @@ QQuickContext2DFBOTexture::QQuickContext2DFBOTexture()
, m_multisampledFbo(0)
, m_paint_device(0)
{
+ m_displayTextures[0] = 0;
+ m_displayTextures[1] = 0;
+ m_displayTexture = -1;
}
QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
@@ -403,17 +413,52 @@ QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
delete m_fbo;
delete m_multisampledFbo;
delete m_paint_device;
+
+ glDeleteTextures(2, m_displayTextures);
}
-QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
+QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
{
- return npotAdjustedSize(ts);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(lastTexture);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_fbo) {
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ texture->setOwnsTexture(false);
+ m_dirtyTexture = true;
+ }
+
+ if (m_dirtyTexture) {
+ if (!m_context->glContext()) {
+ // on a rendering thread, use the fbo directly...
+ texture->setTextureId(m_fbo->texture());
+ } else {
+ // on GUI or custom thread, use display textures...
+ m_displayTexture = m_displayTexture == 0 ? 1 : 0;
+ texture->setTextureId(m_displayTextures[m_displayTexture]);
+ }
+ texture->setTextureSize(m_fbo->size());
+ m_dirtyTexture = false;
+ }
+
+ }
+
+ if (m_onCustomThread) {
+ m_condition.wakeOne();
+ m_mutex.unlock();
+ }
+
+ return texture;
}
-void QQuickContext2DFBOTexture::bind()
+QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
{
- glBindTexture(GL_TEXTURE_2D, textureId());
- updateBindOptions();
+ return npotAdjustedSize(ts);
}
QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
@@ -424,20 +469,6 @@ QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
, qreal(m_canvasWindow.height()) / m_fboSize.height());
}
-
-int QQuickContext2DFBOTexture::textureId() const
-{
- return m_fbo? m_fbo->texture() : 0;
-}
-
-
-bool QQuickContext2DFBOTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- m_dirtyTexture = false;
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DFBOTexture::createTile() const
{
return new QQuickContext2DFBOTile();
@@ -461,7 +492,6 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
void QQuickContext2DFBOTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
-
if (!m_fbo) {
m_context->setGrabbedImage(QImage());
return;
@@ -531,7 +561,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
} else {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
-
m_fbo = new QOpenGLFramebufferObject(m_fboSize, format);
}
}
@@ -541,7 +570,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
else
m_fbo->bind();
-
if (!m_paint_device) {
QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
gl_device->setPaintFlipped(true);
@@ -557,25 +585,47 @@ void QQuickContext2DFBOTexture::endPainting()
QQuickContext2DTexture::endPainting();
if (m_multisampledFbo)
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo);
+
+ if (m_context->glContext()) {
+ /* When rendering happens on the render thread, the fbo's texture is
+ * used directly for display. If we are on the GUI thread or a
+ * dedicated Canvas render thread, we need to decouple the FBO from
+ * the texture we are displaying in the SG rendering thread to avoid
+ * stalls and read/write issues in the GL pipeline as the FBO's texture
+ * could then potentially be used in different threads.
+ *
+ * We could have gotten away with only one display texture, but this
+ * would have implied that beginPainting would have to wait for SG
+ * to release that texture.
+ */
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_displayTextures[0] == 0) {
+ m_displayTexture = 1;
+ glGenTextures(2, m_displayTextures);
+ }
+
+ m_fbo->bind();
+ GLuint target = m_displayTexture == 0 ? 1 : 0;
+ glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0);
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+ }
+
+ m_fbo->bindDefault();
}
QQuickContext2DImageTexture::QQuickContext2DImageTexture()
: QQuickContext2DTexture()
- , m_texture(0)
{
}
QQuickContext2DImageTexture::~QQuickContext2DImageTexture()
{
- if (m_texture && m_texture->thread() != QThread::currentThread())
- m_texture->deleteLater();
- else
- delete m_texture;
-}
-
-int QQuickContext2DImageTexture::textureId() const
-{
- return imageTexture()->textureId();
}
QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
@@ -583,22 +633,6 @@ QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
return QQuickCanvasItem::Image;
}
-void QQuickContext2DImageTexture::bind()
-{
- imageTexture()->setFiltering(filtering());
- imageTexture()->bind();
-}
-
-bool QQuickContext2DImageTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- if (m_dirtyTexture) {
- imageTexture()->setImage(m_image);
- m_dirtyTexture = false;
- }
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DImageTexture::createTile() const
{
return new QQuickContext2DImageTile();
@@ -608,19 +642,32 @@ void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
Q_ASSERT(m_context);
- QImage grabbed = m_image.copy(rf.toRect());
+ QImage grabbed = m_displayImage.copy(rf.toRect());
m_context->setGrabbedImage(grabbed);
}
-QSGPlainTexture *QQuickContext2DImageTexture::imageTexture() const
+QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
{
- if (!m_texture) {
- QQuickContext2DImageTexture *that = const_cast<QQuickContext2DImageTexture *>(this);
- that->m_texture = new QSGPlainTexture;
- that->m_texture->setOwnsTexture(true);
- that->m_texture->setHasMipmaps(false);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(last);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ m_dirtyTexture = true;
+ }
+ if (m_dirtyTexture) {
+ texture->setImage(m_displayImage);
+ m_dirtyTexture = false;
}
- return m_texture;
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+
+ return texture;
}
QPaintDevice* QQuickContext2DImageTexture::beginPainting()
@@ -639,6 +686,16 @@ QPaintDevice* QQuickContext2DImageTexture::beginPainting()
return &m_image;
}
+void QQuickContext2DImageTexture::endPainting()
+{
+ QQuickContext2DTexture::endPainting();
+ if (m_onCustomThread)
+ m_mutex.lock();
+ m_displayImage = m_image;
+ if (m_onCustomThread)
+ m_mutex.unlock();
+}
+
void QQuickContext2DImageTexture::compositeTile(QQuickContext2DTile* tile)
{
Q_ASSERT(!tile->dirty());
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 2a5b7a318a..cf0e8e3fa9 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -58,16 +58,44 @@ QT_BEGIN_NAMESPACE
class QQuickContext2DTile;
class QQuickContext2DCommandBuffer;
-class QQuickContext2DTexture : public QSGDynamicTexture
+class QQuickContext2DTexture : public QObject
{
Q_OBJECT
public:
+ class PaintEvent : public QEvent {
+ public:
+ PaintEvent(QQuickContext2DCommandBuffer *b) : QEvent(QEvent::Type(QEvent::User + 1)), buffer(b) {}
+ QQuickContext2DCommandBuffer *buffer;
+ };
+
+ class CanvasChangeEvent : public QEvent {
+ public:
+ CanvasChangeEvent(const QSize &cSize,
+ const QSize &tSize,
+ const QRect &cWindow,
+ const QRect &dRect,
+ bool sm,
+ bool aa)
+ : QEvent(QEvent::Type(QEvent::User + 2))
+ , canvasSize(cSize)
+ , tileSize(tSize)
+ , canvasWindow(cWindow)
+ , dirtyRect(dRect)
+ , smooth(sm)
+ , antialiasing(aa)
+ {
+ }
+ QSize canvasSize;
+ QSize tileSize;
+ QRect canvasWindow;
+ QRect dirtyRect;
+ bool smooth;
+ bool antialiasing;
+ };
+
QQuickContext2DTexture();
~QQuickContext2DTexture();
- virtual bool hasAlphaChannel() const {return true;}
- virtual bool hasMipmaps() const {return false;}
- virtual QSize textureSize() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const = 0;
static QRect tiledRect(const QRectF& window, const QSize& tileSize);
@@ -78,15 +106,20 @@ public:
void setAntialiasing(bool antialiasing);
bool setDirtyRect(const QRect &dirtyRect);
bool canvasDestroyed();
+ void setOnCustomThread(bool is) { m_onCustomThread = is; }
+
+ // Called during sync() on the scene graph thread while GUI is blocked.
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
+ bool event(QEvent *e);
Q_SIGNALS:
void textureChanged();
public Q_SLOTS:
- void markDirtyTexture();
- void setItem(QQuickCanvasItem* item);
void canvasChanged(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void paint(QQuickContext2DCommandBuffer *ccb);
+ void markDirtyTexture();
+ void setItem(QQuickCanvasItem* item);
virtual void grabImage(const QRectF& region = QRectF()) = 0;
protected:
@@ -110,13 +143,16 @@ protected:
QSize m_tileSize;
QRect m_canvasWindow;
- uint m_dirtyCanvas : 1;
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+
uint m_canvasWindowChanged : 1;
uint m_dirtyTexture : 1;
uint m_smooth : 1;
uint m_antialiasing : 1;
uint m_tiledCanvas : 1;
uint m_painting : 1;
+ uint m_onCustomThread : 1; // Not GUI and not SGRender
};
class QQuickContext2DFBOTexture : public QQuickContext2DTexture
@@ -126,17 +162,16 @@ class QQuickContext2DFBOTexture : public QQuickContext2DTexture
public:
QQuickContext2DFBOTexture();
~QQuickContext2DFBOTexture();
- virtual int textureId() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
virtual void endPainting();
QRectF normalizedTextureSubRect() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
virtual void compositeTile(QQuickContext2DTile* tile);
- virtual void bind();
QSize adjustedTileSize(const QSize &ts);
+ QSGTexture *textureForNextFrame(QSGTexture *);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
@@ -144,10 +179,12 @@ private:
bool doMultisampling() const;
QOpenGLFramebufferObject *m_fbo;
QOpenGLFramebufferObject *m_multisampledFbo;
- QMutex m_mutex;
- QWaitCondition m_condition;
QSize m_fboSize;
QPaintDevice *m_paint_device;
+
+
+ GLuint m_displayTextures[2];
+ int m_displayTexture;
};
class QSGPlainTexture;
@@ -158,24 +195,23 @@ class QQuickContext2DImageTexture : public QQuickContext2DTexture
public:
QQuickContext2DImageTexture();
~QQuickContext2DImageTexture();
- virtual int textureId() const;
- virtual void bind();
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
+ virtual void endPainting();
virtual void compositeTile(QQuickContext2DTile* tile);
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
private:
- QSGPlainTexture *imageTexture() const;
QImage m_image;
+ QImage m_displayImage;
QPainter m_painter;
- QSGPlainTexture* m_texture;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 3996512f9d..41cdb3526b 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -39,6 +39,7 @@ HEADERS += \
$$PWD/qquickpincharea_p_p.h \
$$PWD/qquickflickable_p.h \
$$PWD/qquickflickable_p_p.h \
+ $$PWD/qquickflickablebehavior_p.h \
$$PWD/qquicklistview_p.h \
$$PWD/qquickrepeater_p.h \
$$PWD/qquickrepeater_p_p.h \
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ae174d86e0..fa18d4aa30 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -41,6 +41,7 @@
#include "qquickflickable_p.h"
#include "qquickflickable_p_p.h"
+#include "qquickflickablebehavior_p.h"
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
@@ -58,52 +59,6 @@
QT_BEGIN_NAMESPACE
-// The maximum number of pixels a flick can overshoot
-#ifndef QML_FLICK_OVERSHOOT
-#define QML_FLICK_OVERSHOOT 150
-#endif
-
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 3
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
-// The default deceleration of a flick.
-#ifndef QML_FLICK_DEFAULTDECELERATION
-#define QML_FLICK_DEFAULTDECELERATION 1500
-#endif
-
-// How much faster to decelerate when overshooting
-#ifndef QML_FLICK_OVERSHOOTFRICTION
-#define QML_FLICK_OVERSHOOTFRICTION 8
-#endif
-
-// Multiflick acceleration minimum flick velocity threshold
-#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
-#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
-#endif
-
-// Multiflick acceleration minimum contentSize/viewSize ratio
-#ifndef QML_FLICK_MULTIFLICK_RATIO
-#define QML_FLICK_MULTIFLICK_RATIO 10
-#endif
-
-// Multiflick acceleration maximum velocity multiplier
-#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
-#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
-#endif
-
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
static const int FlickThreshold = 15;
@@ -508,16 +463,27 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
data.vTime = timeline.time();
}
+static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
+{
+ if (a == 0.0 || b == 0.0) {
+ // qFuzzyCompare is broken
+ a += 1.0;
+ b += 1.0;
+ }
+ return a <= b || qFuzzyCompare(a, b);
+}
+
void QQuickFlickablePrivate::updateBeginningEnd()
{
Q_Q(QQuickFlickable);
bool atBoundaryChange = false;
// Vertical
- const int maxyextent = int(-q->maxYExtent());
+ const qreal maxyextent = -q->maxYExtent();
+ const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = (ypos <= -q->minYExtent());
- bool atEnd = (maxyextent <= ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
+ bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -529,10 +495,11 @@ void QQuickFlickablePrivate::updateBeginningEnd()
}
// Horizontal
- const int maxxextent = int(-q->maxXExtent());
+ const qreal maxxextent = -q->maxXExtent();
+ const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = (xpos <= -q->minXExtent());
- atEnd = (maxxextent <= xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
+ atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -1046,17 +1013,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
// the estimate to be altered
const qreal minY = vData.dragMinBound + vData.startMargin;
const qreal maxY = vData.dragMaxBound - vData.endMargin;
- if (newY > minY)
- newY = minY + (newY - minY) / 2;
- if (newY < maxY && maxY - minY <= 0)
- newY = maxY + (newY - maxY) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY <= maxY) {
- newY = maxY;
- rejectY = vData.pressPos == maxY && dy < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY >= minY) {
- newY = minY;
- rejectY = vData.pressPos == minY && dy > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newY <= maxY) {
+ newY = maxY;
+ rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
+ }
+ if (newY >= minY) {
+ newY = minY;
+ rejectY = vData.pressPos == minY && vData.move.value() == minY && dy > 0;
+ }
+ } else {
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY <= 0)
+ newY = maxY + (newY - maxY) / 2;
}
if (!rejectY && stealMouse && dy != 0.0) {
clearTimeline();
@@ -1077,17 +1047,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
const qreal minX = hData.dragMinBound + hData.startMargin;
const qreal maxX = hData.dragMaxBound - hData.endMargin;
- if (newX > minX)
- newX = minX + (newX - minX) / 2;
- if (newX < maxX && maxX - minX <= 0)
- newX = maxX + (newX - maxX) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX <= maxX) {
- newX = maxX;
- rejectX = hData.pressPos == maxX && dx < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX >= minX) {
- newX = minX;
- rejectX = hData.pressPos == minX && dx > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newX <= maxX) {
+ newX = maxX;
+ rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
+ }
+ if (newX >= minX) {
+ newX = minX;
+ rejectX = hData.pressPos == minX && hData.move.value() == minX && dx > 0;
+ }
+ } else {
+ if (newX > minX)
+ newX = minX + (newX - minX) / 2;
+ if (newX < maxX && maxX - minX <= 0)
+ newX = maxX + (newX - maxX) / 2;
}
if (!rejectX && stealMouse && dx != 0.0) {
@@ -2075,12 +2048,13 @@ bool QQuickFlickable::sendMouseEvent(QQuickItem *item, QMouseEvent *event)
if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || grabberDisabled) {
d->clearDelayedPress();
grabMouse();
+ } else if (d->delayedPressEvent) {
+ grabMouse();
}
- // Do not accept this event when filtering, as this would force the mouse grab to the child
const bool filtered = stealThisEvent || d->delayedPressEvent || grabberDisabled;
if (filtered) {
- event->setAccepted(false);
+ event->setAccepted(true);
}
return filtered;
} else if (d->lastPosTime != -1) {
diff --git a/src/quick/items/qquickflickablebehavior_p.h b/src/quick/items/qquickflickablebehavior_p.h
new file mode 100644
index 0000000000..317d6512e6
--- /dev/null
+++ b/src/quick/items/qquickflickablebehavior_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Research In Motion.
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFLICKABLEBEHAVIOR_H
+#define QQUICKFLICKABLEBEHAVIOR_H
+
+/* ### Platform specific flickable mechanics are defined either here, or in
+ mkspec files. Long-term (QtQuick 3) Flickable needs to allow such
+ mechanic details to be controlled via QML so that platforms can easily
+ load custom behavior at QML compile time.
+*/
+
+// The maximum number of pixels a flick can overshoot
+#ifndef QML_FLICK_OVERSHOOT
+#define QML_FLICK_OVERSHOOT 150
+#endif
+
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 0
+#endif
+
+// The default maximum velocity of a flick.
+#ifndef QML_FLICK_DEFAULTMAXVELOCITY
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTMAXVELOCITY 10000
+#else
+#define QML_FLICK_DEFAULTMAXVELOCITY 2500
+#endif
+#endif
+
+// The default deceleration of a flick.
+#ifndef QML_FLICK_DEFAULTDECELERATION
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTDECELERATION 5000
+#else
+#define QML_FLICK_DEFAULTDECELERATION 1500
+#endif
+#endif
+
+// How much faster to decelerate when overshooting
+#ifndef QML_FLICK_OVERSHOOTFRICTION
+#define QML_FLICK_OVERSHOOTFRICTION 8
+#endif
+
+// Multiflick acceleration minimum flick velocity threshold
+#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
+#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
+#endif
+
+// Multiflick acceleration minimum contentSize/viewSize ratio
+#ifndef QML_FLICK_MULTIFLICK_RATIO
+#define QML_FLICK_MULTIFLICK_RATIO 10
+#endif
+
+// Multiflick acceleration maximum velocity multiplier
+#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
+#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
+#endif
+
+#endif //QQUICKFLICKABLEBEHAVIOR_H
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 96797a7588..d6dd7cb61a 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -6572,15 +6572,7 @@ void QQuickItem::grabMouse()
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
- if (windowPriv->mouseGrabberItem == this)
- return;
-
- QQuickItem *oldGrabber = windowPriv->mouseGrabberItem;
- windowPriv->mouseGrabberItem = this;
- if (oldGrabber) {
- QEvent ev(QEvent::UngrabMouse);
- d->window->sendEvent(oldGrabber, &ev);
- }
+ windowPriv->setMouseGrabber(this);
}
/*!
@@ -6960,7 +6952,10 @@ bool QQuickItem::event(QEvent *ev)
touchEvent(static_cast<QTouchEvent*>(ev));
break;
case QEvent::StyleAnimationUpdate:
- update();
+ if (isVisible()) {
+ ev->accept();
+ update();
+ }
break;
case QEvent::HoverEnter:
hoverEnterEvent(static_cast<QHoverEvent*>(ev));
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 3987ff0cfb..ef5c63e40f 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -451,7 +451,7 @@ public:
// dirtyToString()
TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position |
- Size | Window,
+ Window,
ComplexTransformUpdateMask = Transform | Window,
ContentUpdateMask = Size | Content | Smooth | Window | Antialiasing,
ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Window
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 5931d6c09e..ad026a3152 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -334,6 +334,21 @@ public:
}
}
+ void setSections(const QString &prev, const QString &sect, const QString &next) {
+ bool prevChanged = prev != m_prevSection;
+ bool sectChanged = sect != m_section;
+ bool nextChanged = next != m_nextSection;
+ m_prevSection = prev;
+ m_section = sect;
+ m_nextSection = next;
+ if (prevChanged)
+ Q_EMIT prevSectionChanged();
+ if (sectChanged)
+ Q_EMIT sectionChanged();
+ if (nextChanged)
+ Q_EMIT nextSectionChanged();
+ }
+
void emitAdd() { Q_EMIT add(); }
void emitRemove() { Q_EMIT remove(); }
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 7f6c7fdbb9..6324d7960a 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -143,7 +143,8 @@ public:
QQuickListView::SnapMode snapMode;
QSmoothedAnimation *highlightPosAnimator;
- QSmoothedAnimation *highlightSizeAnimator;
+ QSmoothedAnimation *highlightWidthAnimator;
+ QSmoothedAnimation *highlightHeightAnimator;
qreal highlightMoveVelocity;
qreal highlightResizeVelocity;
int highlightResizeDuration;
@@ -168,7 +169,7 @@ public:
, visiblePos(0)
, averageSize(100.0), spacing(0.0)
, snapMode(QQuickListView::NoSnap)
- , highlightPosAnimator(0), highlightSizeAnimator(0)
+ , highlightPosAnimator(0), highlightWidthAnimator(0), highlightHeightAnimator(0)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
@@ -177,7 +178,8 @@ public:
}
~QQuickListViewPrivate() {
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
}
friend class QQuickViewSection;
@@ -487,7 +489,7 @@ QString QQuickListViewPrivate::sectionAt(int modelIndex)
return item->attached->section();
QString section;
- if (sectionCriteria) {
+ if (sectionCriteria && modelIndex >= 0 && modelIndex < itemCount) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
section = sectionCriteria->sectionString(propValue);
}
@@ -565,19 +567,19 @@ FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
// initialise attached properties
if (sectionCriteria) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
- listItem->attached->setSection(sectionCriteria->sectionString(propValue));
+ QString section = sectionCriteria->sectionString(propValue);
+ QString prevSection;
+ QString nextSection;
if (modelIndex > 0) {
if (FxViewItem *item = itemBefore(modelIndex))
- listItem->attached->setPrevSection(item->attached->section());
+ prevSection = item->attached->section();
else
- listItem->attached->setPrevSection(sectionAt(modelIndex-1));
+ prevSection = sectionAt(modelIndex-1);
}
if (modelIndex < model->count()-1) {
- if (FxViewItem *item = visibleItem(modelIndex+1))
- listItem->attached->setNextSection(static_cast<QQuickListViewAttached*>(item->attached)->section());
- else
- listItem->attached->setNextSection(sectionAt(modelIndex+1));
+ nextSection = sectionAt(modelIndex+1);
}
+ listItem->attached->setSections(prevSection, section, nextSection);
}
return listItem;
@@ -855,9 +857,11 @@ void QQuickListViewPrivate::createHighlight()
highlight = 0;
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
highlightPosAnimator = 0;
- highlightSizeAnimator = 0;
+ highlightWidthAnimator = 0;
+ highlightHeightAnimator = 0;
changed = true;
}
@@ -878,11 +882,15 @@ void QQuickListViewPrivate::createHighlight()
highlightPosAnimator->velocity = highlightMoveVelocity;
highlightPosAnimator->userDuration = highlightMoveDuration;
- const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
- highlightSizeAnimator = new QSmoothedAnimation;
- highlightSizeAnimator->velocity = highlightResizeVelocity;
- highlightSizeAnimator->userDuration = highlightResizeDuration;
- highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
+ highlightWidthAnimator = new QSmoothedAnimation;
+ highlightWidthAnimator->velocity = highlightResizeVelocity;
+ highlightWidthAnimator->userDuration = highlightResizeDuration;
+ highlightWidthAnimator->target = QQmlProperty(item, "width");
+
+ highlightHeightAnimator = new QSmoothedAnimation;
+ highlightHeightAnimator->velocity = highlightResizeVelocity;
+ highlightHeightAnimator->userDuration = highlightResizeDuration;
+ highlightHeightAnimator->target = QQmlProperty(item, "height");
highlight = newHighlight;
changed = true;
@@ -905,7 +913,8 @@ void QQuickListViewPrivate::updateHighlight()
highlightPosAnimator->to = isContentFlowReversed()
? -listItem->itemPosition()-listItem->itemSize()
: listItem->itemPosition();
- highlightSizeAnimator->to = listItem->itemSize();
+ highlightWidthAnimator->to = listItem->item->width();
+ highlightHeightAnimator->to = listItem->item->height();
if (orient == QQuickListView::Vertical) {
if (highlight->item->width() == 0)
highlight->item->setWidth(currentItem->item->width());
@@ -915,7 +924,8 @@ void QQuickListViewPrivate::updateHighlight()
}
highlightPosAnimator->restart();
- highlightSizeAnimator->restart();
+ highlightWidthAnimator->restart();
+ highlightHeightAnimator->restart();
}
updateTrackedItem();
}
@@ -1968,8 +1978,10 @@ void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
if (!autoHighlight) {
if (d->highlightPosAnimator)
d->highlightPosAnimator->stop();
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->stop();
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->stop();
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->stop();
}
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
}
@@ -2296,8 +2308,10 @@ void QQuickListView::setHighlightResizeVelocity(qreal speed)
Q_D(QQuickListView);
if (d->highlightResizeVelocity != speed) {
d->highlightResizeVelocity = speed;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->velocity = d->highlightResizeVelocity;
emit highlightResizeVelocityChanged();
}
}
@@ -2313,8 +2327,10 @@ void QQuickListView::setHighlightResizeDuration(int duration)
Q_D(QQuickListView);
if (d->highlightResizeDuration != duration) {
d->highlightResizeDuration = duration;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->userDuration = d->highlightResizeDuration;
emit highlightResizeDurationChanged();
}
}
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 7d04be2393..b83c21428c 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -106,6 +106,7 @@ void QQuickLoaderPrivate::clear()
component->deleteLater();
component = 0;
}
+ componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -472,6 +473,10 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
d->component = comp;
+ if (comp) {
+ if (QQmlData *ddata = QQmlData::get(comp))
+ d->componentStrongReference = ddata->jsWrapper.value();
+ }
d->loadingFromSource = false;
if (d->active)
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9c94b4ce38..32c271222d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -106,6 +106,7 @@ public:
QQuickItem *item;
QObject *object;
QQmlComponent *component;
+ QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 808c2638e2..438ec29fd0 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -822,6 +822,12 @@ void QQuickMouseArea::ungrabMouse()
d->pressed = 0;
d->stealMouse = false;
setKeepMouseGrab(false);
+
+#ifndef QT_NO_DRAGANDDROP
+ if (d->drag)
+ d->drag->setActive(false);
+#endif
+
emit canceled();
emit pressedChanged();
emit pressedButtonsChanged();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1f41fe04e5..0080f54d20 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -42,6 +42,7 @@
#include "qquickpathview_p.h"
#include "qquickpathview_p_p.h"
#include "qquickwindow.h"
+#include "qquickflickablebehavior_p.h" //Contains flicking behavior defines
#include <QtQuick/private/qquickstate_p.h>
#include <private/qqmlglobal_p.h>
@@ -56,22 +57,6 @@
#include <QtCore/qmath.h>
#include <math.h>
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 1
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index 3ab13dbbc7..a615cb6f91 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -146,7 +146,6 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
continue;
}
}
- qWarning("ShaderEffect: source or provider missing when binding textures");
glBindTexture(GL_TEXTURE_2D, 0);
} else if (d.specialType == UniformData::Opacity) {
program()->setUniformValue(loc, state.opacity());
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index e076a342df..98203c51e5 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -158,16 +158,24 @@ QQuickShaderEffectTexture::QQuickShaderEffectTexture(QQuickItem *shaderSource)
QQuickShaderEffectTexture::~QQuickShaderEffectTexture()
{
- if (m_renderer)
- disconnect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
+ invalidated();
+}
+
+void QQuickShaderEffectTexture::invalidated()
+{
delete m_renderer;
+ m_renderer = 0;
delete m_fbo;
delete m_secondaryFbo;
+ m_fbo = m_secondaryFbo = 0;
#ifdef QSG_DEBUG_FBO_OVERLAY
delete m_debugOverlay;
+ m_debugOverlay = 0;
#endif
- if (m_transparentTexture)
+ if (m_transparentTexture) {
glDeleteTextures(1, &m_transparentTexture);
+ m_transparentTexture = 0;
+ }
}
int QQuickShaderEffectTexture::textureId() const
@@ -609,6 +617,7 @@ void QQuickShaderEffectSource::ensureTexture()
"Cannot be used outside the rendering thread");
m_texture = new QQuickShaderEffectTexture(this);
+ connect(QQuickItemPrivate::get(this)->window, SIGNAL(sceneGraphInvalidated()), m_texture, SLOT(invalidated()), Qt::DirectConnection);
connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update()));
connect(m_texture, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted()));
}
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 6218775700..efa963fe64 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -124,6 +124,7 @@ Q_SIGNALS:
public Q_SLOTS:
void markDirtyTexture();
+ void invalidated();
private:
void grab();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9c153febb6..beb2039924 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -296,44 +296,6 @@ qreal QQuickTextPrivate::getImplicitHeight() const
The default is true.
*/
-/*!
- \qmlproperty enumeration QtQuick::Text::renderType
-
- Override the default rendering type for this component.
-
- Supported render types are:
- \list
- \li Text.QtRendering - the default
- \li Text.NativeRendering
- \endlist
-
- Select Text.NativeRendering if you prefer text to look native on the target platform and do
- not require advanced features such as transformation of the text. Using such features in
- combination with the NativeRendering render type will lend poor and sometimes pixelated
- results.
-
- On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
- and QtRendering is always used.
-*/
-QQuickText::RenderType QQuickText::renderType() const
-{
- Q_D(const QQuickText);
- return d->renderType;
-}
-
-void QQuickText::setRenderType(QQuickText::RenderType renderType)
-{
- Q_D(QQuickText);
- if (d->renderType == renderType)
- return;
-
- d->renderType = renderType;
- emit renderTypeChanged();
-
- if (isComponentComplete())
- d->updateLayout();
-}
-
void QQuickText::q_imagesLoaded()
{
Q_D(QQuickText);
@@ -640,17 +602,6 @@ void QQuickTextLine::setY(qreal y)
m_line->setPosition(QPointF(m_line->x(), y));
}
-/*!
- \qmlmethod QtQuick::Text::doLayout()
-
- Triggers a re-layout of the displayed text.
-*/
-void QQuickText::doLayout()
-{
- Q_D(QQuickText);
- d->updateSize();
-}
-
bool QQuickTextPrivate::isLineLaidOutConnected()
{
Q_Q(QQuickText);
@@ -2683,4 +2634,53 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
d->processHoverEvent(event);
}
+/*!
+ \qmlproperty enumeration QtQuick::Text::renderType
+
+ Override the default rendering type for this component.
+
+ Supported render types are:
+ \list
+ \li Text.QtRendering - the default
+ \li Text.NativeRendering
+ \endlist
+
+ Select Text.NativeRendering if you prefer text to look native on the target platform and do
+ not require advanced features such as transformation of the text. Using such features in
+ combination with the NativeRendering render type will lend poor and sometimes pixelated
+ results.
+
+ On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
+ and QtRendering is always used.
+*/
+QQuickText::RenderType QQuickText::renderType() const
+{
+ Q_D(const QQuickText);
+ return d->renderType;
+}
+
+void QQuickText::setRenderType(QQuickText::RenderType renderType)
+{
+ Q_D(QQuickText);
+ if (d->renderType == renderType)
+ return;
+
+ d->renderType = renderType;
+ emit renderTypeChanged();
+
+ if (isComponentComplete())
+ d->updateLayout();
+}
+
+/*!
+ \qmlmethod QtQuick::Text::doLayout()
+
+ Triggers a re-layout of the displayed text.
+*/
+void QQuickText::doLayout()
+{
+ Q_D(QQuickText);
+ d->updateSize();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index d4427eb47e..1dd1dfa57e 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1679,6 +1679,7 @@ bool QQuickTextInput::event(QEvent* ev)
|| ke == QKeySequence::SelectAll
|| ke == QKeySequence::SelectEndOfDocument) {
ke->accept();
+ return true;
} else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
|| ke->modifiers() == Qt::KeypadModifier) {
if (ke->key() < Qt::Key_Escape) {
@@ -1692,6 +1693,7 @@ bool QQuickTextInput::event(QEvent* ev)
case Qt::Key_Backspace:
case Qt::Key_Left:
case Qt::Key_Right:
+ ke->accept();
return true;
default:
break;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 10906dd64c..63a3b5d820 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -600,6 +600,28 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
return false;
}
+void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
+{
+ Q_Q(QQuickWindow);
+ if (mouseGrabberItem == grabber)
+ return;
+
+ QQuickItem *oldGrabber = mouseGrabberItem;
+ mouseGrabberItem = grabber;
+
+ if (touchMouseId != -1) {
+ // update the touch item for mouse touch id to the new grabber
+ itemForTouchPointId.remove(touchMouseId);
+ if (grabber)
+ itemForTouchPointId[touchMouseId] = grabber;
+ }
+
+ if (oldGrabber) {
+ QEvent ev(QEvent::UngrabMouse);
+ q->sendEvent(oldGrabber, &ev);
+ }
+}
+
void QQuickWindowPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
{
QMatrix4x4 transformMatrix(transform);
@@ -661,6 +683,7 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *newActiveFocusItem = 0;
QVarLengthArray<QQuickItem *, 20> changed;
@@ -737,7 +760,8 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -764,6 +788,7 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
return;//No focus, nothing to do.
}
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *oldActiveFocusItem = 0;
QQuickItem *newActiveFocusItem = 0;
@@ -820,7 +845,8 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -1218,8 +1244,11 @@ bool QQuickWindow::event(QEvent *e)
case QEvent::TouchEnd: {
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->translateTouchEvent(touch);
- // return in order to avoid the QWindow::event below
- return d->deliverTouchEvent(touch);
+ d->deliverTouchEvent(touch);
+ // we consume all touch events ourselves to avoid duplicate
+ // mouse delivery by QtGui mouse synthesis
+ e->accept();
+ return true;
}
break;
case QEvent::TouchCancel:
@@ -1798,7 +1827,10 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
// First check whether the parent wants to be a filter,
// and if the parent accepts the event we are done.
if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
- event->accept();
+ // If the touch was accepted (regardless by whom or in what form),
+ // update acceptedNewPoints
+ foreach (int id, matchingNewPoints)
+ acceptedNewPoints->insert(id);
return true;
}
@@ -2303,6 +2335,8 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->groupNode = 0;
p->paintNode = 0;
+
+ p->dirty(QQuickItemPrivate::Window);
}
for (int ii = 0; ii < p->childItems.count(); ++ii)
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index c23745b5f1..418633b6ac 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -127,6 +127,7 @@ public:
QPointF lastMousePosition;
bool translateTouchToMouse(QQuickItem *item, QTouchEvent *event);
void translateTouchEvent(QTouchEvent *touchEvent);
+ void setMouseGrabber(QQuickItem *grabber);
static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index b91edc2fd5..44a4bf3db6 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -45,12 +45,50 @@
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlEngine>
+#include <private/qguiapplication_p.h>
+#include <private/qqmlengine_p.h>
+#include <qpa/qplatformintegration.h>
+
QT_BEGIN_NAMESPACE
class QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
{
Q_INTERFACES(QQmlParserStatus)
Q_OBJECT
+
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+
+public:
+ QQuickWindowQmlImpl(QWindow *parent = 0)
+ : QQuickWindow(parent)
+ , m_complete(false)
+ , m_visible(isVisible())
+ , m_visibility(AutomaticVisibility)
+ {
+ connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
+ connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
+ }
+
+ void setVisible(bool visible) {
+ if (!m_complete)
+ m_visible = visible;
+ else
+ QQuickWindow::setVisible(visible);
+ }
+
+ void setVisibility(Visibility visibility)
+ {
+ if (!m_complete)
+ m_visibility = visibility;
+ else
+ QQuickWindow::setVisibility(visibility);
+ }
+
+Q_SIGNALS:
+ void visibleChanged(bool arg);
+ void visibilityChanged(QWindow::Visibility visibility);
+
protected:
void classBegin() {
//Give QQuickView behavior when created from QML with QQmlApplicationEngine
@@ -61,7 +99,47 @@ protected:
}
}
- void componentComplete() {}
+ void componentComplete() {
+ m_complete = true;
+
+ // We have deferred window creation until we have the full picture of what
+ // the user wanted in terms of window state, geometry, visibility, etc.
+
+ if ((m_visibility == Hidden && m_visible) || (m_visibility > AutomaticVisibility && !m_visible)) {
+ QQmlData *data = QQmlData::get(this);
+ Q_ASSERT(data && data->context);
+
+ QQmlError error;
+ error.setObject(this);
+
+ const QQmlContextData* urlContext = data->context;
+ while (urlContext && urlContext->url.isEmpty())
+ urlContext = urlContext->parent;
+ error.setUrl(urlContext ? urlContext->url : QUrl());
+
+ QString objectId = data->context->findObjectId(this);
+ if (!objectId.isEmpty())
+ error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
+ "Conflicting properties 'visible' and 'visibility' for Window '%1'").arg(objectId));
+ else
+ error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
+ "Conflicting properties 'visible' and 'visibility'"));
+
+ QQmlEnginePrivate::get(data->context->engine)->warning(error);
+ }
+
+ if (m_visibility == AutomaticVisibility) {
+ setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags()));
+ setVisible(m_visible);
+ } else {
+ setVisibility(m_visibility);
+ }
+ }
+
+private:
+ bool m_complete;
+ bool m_visible;
+ Visibility m_visibility;
};
void QQuickWindowModule::defineModule()
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 79b5de72c0..8ff68e20bc 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -590,15 +590,18 @@ void Element::computeBounds()
}
bounds.map(*node->matrix());
- if (!qIsFinite(bounds.tl.x))
+ if (!qIsFinite(bounds.tl.x) || bounds.tl.x == FLT_MAX)
bounds.tl.x = -FLT_MAX;
- if (!qIsFinite(bounds.tl.y))
+ if (!qIsFinite(bounds.tl.y) || bounds.tl.y == FLT_MAX)
bounds.tl.y = -FLT_MAX;
- if (!qIsFinite(bounds.br.x))
+ if (!qIsFinite(bounds.br.x) || bounds.br.x == -FLT_MAX)
bounds.br.x = FLT_MAX;
- if (!qIsFinite(bounds.br.y))
+ if (!qIsFinite(bounds.br.y) || bounds.br.y == -FLT_MAX)
bounds.br.y = FLT_MAX;
+ Q_ASSERT(bounds.tl.x <= bounds.br.x);
+ Q_ASSERT(bounds.tl.y <= bounds.br.y);
+
boundsOutsideFloatRange = bounds.isOutsideFloatRange();
}
@@ -2112,6 +2115,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
offset += a.tupleSize * size_of_type(a.type);
}
+ if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES)
+ glLineWidth(g->lineWidth());
+
if (g->indexCount())
glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), iOffset);
else
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 95e111552d..5404b669a0 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -104,8 +104,6 @@ struct Rect {
tl.y = pt.y;
if (pt.y > br.y)
br.y = pt.y;
- Q_ASSERT(tl.x <= br.x);
- Q_ASSERT(tl.y <= br.y);
}
void operator |= (const Rect &r) {
@@ -117,8 +115,6 @@ struct Rect {
br.x = r.br.x;
if (r.br.y > br.y)
br.y = r.br.y;
- Q_ASSERT(tl.x <= br.x);
- Q_ASSERT(tl.y <= br.y);
}
void map(const QMatrix4x4 &m);
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 3c9c353bd8..df70b5c5eb 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
//#define RENDERER_DEBUG
//#define QT_GL_NO_SCISSOR_TEST
-
+static bool qsg_sanity_check = qgetenv("QSG_SANITY_CHECK").toInt();
#ifndef QSG_NO_RENDER_TIMING
static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
@@ -243,9 +243,8 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
bindTime = frameTimer.nsecsElapsed();
#endif
-#ifndef QT_NO_DEBUG
// Sanity check that attribute registers are disabled
- {
+ if (qsg_sanity_check) {
GLint count = 0;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
GLint enabled;
@@ -256,7 +255,6 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
}
}
}
-#endif
render();
#ifndef QSG_NO_RENDER_TIMING
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 52df55fa92..ac1bdb7841 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -238,6 +238,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
m_windows.remove(window);
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (gl)
+ gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 850a463c3e..d779285a44 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -48,6 +48,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
@@ -205,12 +206,14 @@ public:
class WMTryReleaseEvent : public WMWindowEvent
{
public:
- WMTryReleaseEvent(QQuickWindow *win, bool destroy)
+ WMTryReleaseEvent(QQuickWindow *win, bool destroy, QOffscreenSurface *fallback)
: WMWindowEvent(win, WM_TryRelease)
, inDestructor(destroy)
+ , fallbackSurface(fallback)
{}
bool inDestructor;
+ QOffscreenSurface *fallbackSurface;
};
class WMExposeEvent : public WMWindowEvent
@@ -295,7 +298,7 @@ public:
delete sgrc;
}
- void invalidateOpenGL(QQuickWindow *window, bool inDestructor);
+ void invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *backupSurface);
void initializeOpenGL();
bool event(QEvent *);
@@ -362,17 +365,9 @@ bool QSGRenderThread::event(QEvent *e)
case WM_Expose: {
QSG_RT_DEBUG("WM_Expose");
WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
-
- pendingUpdate |= RepaintRequest;
-
Q_ASSERT(!window || window == se->window);
-
+ pendingUpdate |= RepaintRequest;
windowSize = se->size;
- if (window) {
- QSG_RT_DEBUG(" - window already added...");
- return true;
- }
-
window = se->window;
return true; }
@@ -383,7 +378,7 @@ bool QSGRenderThread::event(QEvent *e)
mutex.lock();
if (window) {
- QSG_RT_DEBUG(" - removed one...");
+ QSG_RT_DEBUG(" - removed window...");
window = 0;
}
waitCondition.wakeOne();
@@ -402,10 +397,11 @@ bool QSGRenderThread::event(QEvent *e)
case WM_TryRelease: {
QSG_RT_DEBUG("WM_TryRelease");
mutex.lock();
+ wm->m_locked = true;
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (!window || wme->inDestructor) {
QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
- invalidateOpenGL(wme->window, wme->inDestructor);
+ invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface);
active = gl;
if (sleeping)
stopEventProcessing = true;
@@ -413,6 +409,7 @@ bool QSGRenderThread::event(QEvent *e)
QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
+ wm->m_locked = false;
mutex.unlock();
return true;
}
@@ -453,7 +450,7 @@ bool QSGRenderThread::event(QEvent *e)
return QThread::event(e);
}
-void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
+void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *fallback)
{
QSG_RT_DEBUG("invalidateOpenGL()");
@@ -469,7 +466,13 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
- gl->makeCurrent(window);
+ bool current = gl->makeCurrent(fallback ? static_cast<QSurface *>(fallback) : static_cast<QSurface *>(window));
+ if (!current) {
+#ifndef QT_NO_DEBUG
+ qWarning() << "Scene Graph failed to acquire GL context during cleanup";
+#endif
+ return;
+ }
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
@@ -477,6 +480,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
dd->cleanupNodesOnShutdown();
} else {
QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
+ gl->doneCurrent();
return;
}
@@ -510,7 +514,6 @@ void QSGRenderThread::sync()
if (windowSize.width() > 0 && windowSize.height() > 0)
current = gl->makeCurrent(window);
if (current) {
- gl->makeCurrent(window);
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
d->syncSceneGraph();
@@ -528,7 +531,6 @@ void QSGRenderThread::sync()
QSG_RT_DEBUG(" - window has bad size, waiting...");
}
- QSG_RT_DEBUG(" - window has bad size, waiting...");
waitCondition.wakeOne();
mutex.unlock();
}
@@ -690,7 +692,7 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
: sg(QSGContext::createDefaultContext())
, m_animation_timer(0)
{
-#if defined(QSG_RENDER_LOOP_DEBUG_BASIC) || defined (QSG_RENDER_LOOP_DEBUG_FULL)
+#if defined(QSG_RENDER_LOOP_DEBUG)
qsgrl_timer.start();
#endif
@@ -817,7 +819,6 @@ void QSGThreadedRenderLoop::show(QQuickWindow *window)
win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
win.timerId = 0;
win.updateDuringSync = false;
- win.gotBrokenExposeFromPlatformPlugin = false;
m_windows << win;
}
@@ -883,19 +884,6 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
}
}
-void QSGThreadedRenderLoop::resize(QQuickWindow *window)
-{
- Window *w = windowFor(m_windows, window);
- if (w
- && w->gotBrokenExposeFromPlatformPlugin
- && window->width() > 0 && window->height() > 0
- && w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
- w->gotBrokenExposeFromPlatformPlugin = false;
- handleExposure(w);
- }
-}
-
-
/*!
Will post an event to the render thread that this window should
start to render.
@@ -909,8 +897,6 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
#ifndef QT_NO_DEBUG
qWarning("QSGThreadedRenderLoop: expose event received for window with invalid geometry.");
#endif
- w->gotBrokenExposeFromPlatformPlugin = true;
- return;
}
// Because we are going to bind a GL context to it, make sure it
@@ -994,6 +980,9 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::maybeUpdate(Window *w)
{
+ if (!QCoreApplication::instance())
+ return;
+
Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
"QQuickItem::update()",
"Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
@@ -1052,9 +1041,26 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestru
w->thread->mutex.lock();
if (w->thread->isRunning() && w->thread->active) {
+
+ // The platform window might have been destroyed before
+ // hide/release/windowDestroyed is called, so we need to have a
+ // fallback surface to perform the cleanup of the scene graph
+ // and the OpenGL resources.
+ // QOffscreenSurface must be created on the GUI thread, so we
+ // create it here and pass it on to QSGRenderThread::invalidateGL()
+ QOffscreenSurface *fallback = 0;
+ if (!window->handle()) {
+ QSG_GUI_DEBUG(w->window, " - using fallback surface");
+ fallback = new QOffscreenSurface();
+ fallback->setFormat(window->requestedFormat());
+ fallback->create();
+ }
+
QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
- w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
+ w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor, fallback));
w->thread->waitCondition.wait(&w->thread->mutex);
+
+ delete fallback;
}
w->thread->mutex.unlock();
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 844d180788..5943d0bd08 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -60,7 +60,6 @@ public:
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
- void resize(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
@@ -90,7 +89,6 @@ private:
QSGRenderThread *thread;
int timerId;
uint updateDuringSync : 1;
- uint gotBrokenExposeFromPlatformPlugin : 1;
};
friend class QSGRenderThread;
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 0c128d5cae..0b6d42aca6 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -240,7 +240,11 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
if (window->isExposed())
handleObscurity();
+ if (!m_gl)
+ return;
+
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ m_gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
// If this is the last tracked window, check for persistent SG and GL and
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 8678d106ff..75bf0b6e3c 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -448,6 +448,7 @@ QSGTexture *Texture::removedFromAtlas() const
if (!m_nonatlas_texture) {
m_nonatlas_texture = new QSGPlainTexture();
m_nonatlas_texture->setImage(m_image);
+ m_nonatlas_texture->setFiltering(filtering());
}
return m_nonatlas_texture;
}
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index 244e13888c..fb7c900252 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -123,7 +123,7 @@ bool QQuickApplication::eventFilter(QObject *, QEvent *event)
if (d->isActive != wasActive) {
emit activeChanged();
}
- } else if (event->type() == QEvent::LayoutDirectionChange) {
+ } else if (event->type() == QEvent::ApplicationLayoutDirectionChange) {
Qt::LayoutDirection newDirection = QGuiApplication::layoutDirection();
if (d->direction != newDirection) {
d->direction = newDirection;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 26258fdc5f..055d6b7e29 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -519,6 +519,9 @@ void QQuickPixmapReader::processJobs()
runningJob->loading = true;
QUrl url = runningJob->url;
+ QQmlPixmapProfiler pixmapProfiler;
+ pixmapProfiler.startLoading(url);
+
QSize requestSize = runningJob->requestSize;
locker.unlock();
processJob(runningJob, url, requestSize);
@@ -897,8 +900,7 @@ bool QQuickPixmapReply::event(QEvent *event)
pixmapProfiler.finishLoading(data->url);
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
- if (data->implicitSize.width() > 0)
- pixmapProfiler.setSize(url, data->implicitSize.width(), data->implicitSize.height());
+ pixmapProfiler.setSize(url, data->requestSize.width() > 0 ? data->requestSize : data->implicitSize);
} else {
pixmapProfiler.errorLoading(data->url);
data->errorString = de->errorString;
@@ -968,8 +970,6 @@ void QQuickPixmapData::addToCache()
inCache = true;
QQmlPixmapProfiler pixmapProfiler;
pixmapProfiler.cacheCountChanged(url, pixmapStore()->m_cache.count());
- if (implicitSize.width() > 0)
- pixmapProfiler.setSize(url, implicitSize.width(), implicitSize.height());
}
}
@@ -1033,17 +1033,6 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
if (localFile.isEmpty())
return 0;
- // check for "retina" high-dpi and use @2x file if it exixts
- if (qApp->devicePixelRatio() > 1) {
- const int dotIndex = localFile.lastIndexOf(QLatin1Char('.'));
- if (dotIndex != -1) {
- QString retinaFile = localFile;
- retinaFile.insert(dotIndex, QStringLiteral("@2x"));
- if (QFile(retinaFile).exists())
- localFile = retinaFile;
- }
- }
-
QFile f(localFile);
QSize readSize;
QString errorString;
@@ -1256,8 +1245,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
pixmapProfiler.finishLoading(url);
- if (d->implicitSize.width() > 0)
- QQmlPixmapProfiler().setSize(url, d->implicitSize.width(), d->implicitSize.height());
+ pixmapProfiler.setSize(url, d->requestSize.width() > 0 ? d->requestSize : d->implicitSize);
if (options & QQuickPixmap::Cache)
d->addToCache();
return;