aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-04-18 14:22:10 +0200
committerUlf Hermann <ulf.hermann@qt.io>2019-04-29 09:16:34 +0000
commit9e5ca92712da3392d1f2957dc1e546cdddd1ce0a (patch)
treea6f12507c544a03f637dd96f150286325ad0d6a4 /src/qml/jit
parent9c25df6dd0412d0e4211370843d8cbb8aef1e512 (diff)
Remove tracing JIT infrastructure
The tracing JIT won't be finished. Therefore, remove the parts that have already been integrated. Change-Id: If72036be904bd7fc17ba9bcba0a317f8ed6cb30d Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
Diffstat (limited to 'src/qml/jit')
-rw-r--r--src/qml/jit/jit.pri31
-rw-r--r--src/qml/jit/qv4baselinejit.cpp59
-rw-r--r--src/qml/jit/qv4baselinejit_p.h58
-rw-r--r--src/qml/jit/qv4blockscheduler.cpp208
-rw-r--r--src/qml/jit/qv4blockscheduler_p.h155
-rw-r--r--src/qml/jit/qv4domtree.cpp436
-rw-r--r--src/qml/jit/qv4domtree_p.h136
-rw-r--r--src/qml/jit/qv4graph.cpp103
-rw-r--r--src/qml/jit/qv4graph_p.h146
-rw-r--r--src/qml/jit/qv4graphbuilder.cpp1683
-rw-r--r--src/qml/jit/qv4graphbuilder_p.h298
-rw-r--r--src/qml/jit/qv4ir.cpp382
-rw-r--r--src/qml/jit/qv4ir_p.h228
-rw-r--r--src/qml/jit/qv4loopinfo.cpp199
-rw-r--r--src/qml/jit/qv4loopinfo_p.h159
-rw-r--r--src/qml/jit/qv4lowering.cpp200
-rw-r--r--src/qml/jit/qv4lowering_p.h107
-rw-r--r--src/qml/jit/qv4mi.cpp251
-rw-r--r--src/qml/jit/qv4mi_p.h627
-rw-r--r--src/qml/jit/qv4miblockset_p.h291
-rw-r--r--src/qml/jit/qv4node.cpp215
-rw-r--r--src/qml/jit/qv4node_p.h626
-rw-r--r--src/qml/jit/qv4operation.cpp770
-rw-r--r--src/qml/jit/qv4operation_p.h567
-rw-r--r--src/qml/jit/qv4runtimesupport_p.h255
-rw-r--r--src/qml/jit/qv4schedulers.cpp912
-rw-r--r--src/qml/jit/qv4schedulers_p.h162
-rw-r--r--src/qml/jit/qv4tracingjit.cpp91
28 files changed, 58 insertions, 9297 deletions
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index bc0d20dba7..503ce0ebcd 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -10,34 +10,3 @@ HEADERS += \
$$PWD/qv4baselinejit_p.h \
$$PWD/qv4baselineassembler_p.h \
$$PWD/qv4assemblercommon_p.h
-
-qtConfig(qml-tracing) {
-SOURCES += \
- $$PWD/qv4ir.cpp \
- $$PWD/qv4operation.cpp \
- $$PWD/qv4node.cpp \
- $$PWD/qv4graph.cpp \
- $$PWD/qv4graphbuilder.cpp \
- $$PWD/qv4lowering.cpp \
- $$PWD/qv4tracingjit.cpp \
- $$PWD/qv4mi.cpp \
- $$PWD/qv4domtree.cpp \
- $$PWD/qv4schedulers.cpp \
- $$PWD/qv4blockscheduler.cpp \
- $$PWD/qv4loopinfo.cpp
-
-HEADERS += \
- $$PWD/qv4ir_p.h \
- $$PWD/qv4operation_p.h \
- $$PWD/qv4runtimesupport_p.h \
- $$PWD/qv4node_p.h \
- $$PWD/qv4graph_p.h \
- $$PWD/qv4graphbuilder_p.h \
- $$PWD/qv4lowering_p.h \
- $$PWD/qv4mi_p.h \
- $$PWD/qv4miblockset_p.h \
- $$PWD/qv4domtree_p.h \
- $$PWD/qv4schedulers_p.h \
- $$PWD/qv4blockscheduler_p.h \
- $$PWD/qv4loopinfo_p.h
-}
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 60880419a6..517f0940e5 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -149,7 +149,7 @@ void BaselineJIT::generate_LoadImport(int index)
as->loadImport(index);
}
-void BaselineJIT::generate_LoadLocal(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadLocal(int index)
{
as->loadLocal(index);
}
@@ -160,7 +160,7 @@ void BaselineJIT::generate_StoreLocal(int index)
as->storeLocal(index);
}
-void BaselineJIT::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
{
as->loadLocal(index, scope);
}
@@ -193,7 +193,7 @@ void BaselineJIT::generate_LoadClosure(int value)
BASELINEJIT_GENERATE_RUNTIME_CALL(Closure, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(2);
@@ -202,7 +202,7 @@ void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadGlobalLookup(int index)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
@@ -211,7 +211,7 @@ void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
@@ -241,7 +241,7 @@ void BaselineJIT::generate_StoreNameStrict(int name)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameStrict, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
+void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
@@ -252,7 +252,7 @@ void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
+void BaselineJIT::generate_StoreElement(int base, int index)
{
STORE_IP();
STORE_ACC();
@@ -264,7 +264,7 @@ void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreElement, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
@@ -275,7 +275,7 @@ void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_GetLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
STORE_ACC();
@@ -353,7 +353,7 @@ void BaselineJIT::generate_Resume(int)
Q_UNREACHABLE();
}
-void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -364,7 +364,7 @@ void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSl
BASELINEJIT_GENERATE_RUNTIME_CALL(CallValue, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -376,7 +376,7 @@ void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithReceiver, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -388,7 +388,7 @@ void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -400,7 +400,7 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -412,7 +412,7 @@ void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -423,7 +423,7 @@ void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlo
BASELINEJIT_GENERATE_RUNTIME_CALL(CallName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(3);
@@ -433,7 +433,7 @@ void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*trac
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPossiblyDirectEval, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -444,8 +444,7 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -456,7 +455,7 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int
BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -775,12 +774,12 @@ void BaselineJIT::generate_Jump(int offset)
labels.insert(as->jump(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpTrue(int offset)
{
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpFalse(int offset)
{
labels.insert(as->jumpFalse(absoluteOffset(offset)));
}
@@ -829,12 +828,12 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
}
void BaselineJIT::generate_UNot() { as->unot(); }
-void BaselineJIT::generate_UPlus(int /*traceSlot*/) { as->toNumber(); }
-void BaselineJIT::generate_UMinus(int /*traceSlot*/) { as->uminus(); }
+void BaselineJIT::generate_UPlus() { as->toNumber(); }
+void BaselineJIT::generate_UMinus() { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
-void BaselineJIT::generate_Increment(int /*traceSlot*/) { as->inc(); }
-void BaselineJIT::generate_Decrement(int /*traceSlot*/) { as->dec(); }
-void BaselineJIT::generate_Add(int lhs, int /*traceSlot*/) { as->add(lhs); }
+void BaselineJIT::generate_Increment() { as->inc(); }
+void BaselineJIT::generate_Decrement() { as->dec(); }
+void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
@@ -858,10 +857,10 @@ void BaselineJIT::generate_Exp(int lhs) {
as->passJSSlotAsArg(lhs, 0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Exp, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_Mul(int lhs, int /*traceSlot*/) { as->mul(lhs); }
+void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
-void BaselineJIT::generate_Mod(int lhs, int /*traceSlot*/) { as->mod(lhs); }
-void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
+void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
+void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 941e0cd408..46622d29e6 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -87,22 +87,22 @@ public:
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
+ void generate_LoadLocal(int index) override;
void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
+ void generate_LoadScopedLocal(int scope, int index) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
+ void generate_LoadName(int name) override;
+ void generate_LoadGlobalLookup(int index) override;
+ void generate_LoadQmlContextPropertyLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
+ void generate_LoadElement(int base) override;
+ void generate_StoreElement(int base, int index) override;
+ void generate_LoadProperty(int name) override;
+ void generate_GetLookup(int index) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -111,16 +111,16 @@ public:
void generate_YieldStar() override;
void generate_Resume(int) override;
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
+ void generate_CallValue(int name, int argc, int argv) override;
+ void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
+ void generate_CallProperty(int name, int base, int argc, int argv) override;
+ void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
+ void generate_CallElement(int base, int index, int argc, int argv) override;
+ void generate_CallName(int name, int argc, int argv) override;
+ void generate_CallPossiblyDirectEval(int argc, int argv) override;
+ void generate_CallGlobalLookup(int index, int argc, int argv) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
@@ -159,8 +159,8 @@ public:
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
+ void generate_JumpTrue(int offset) override;
+ void generate_JumpFalse(int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
void generate_CmpEqNull() override;
@@ -178,12 +178,12 @@ public:
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
void generate_UNot() override;
- void generate_UPlus(int) override;
- void generate_UMinus(int traceSlot) override;
+ void generate_UPlus() override;
+ void generate_UMinus() override;
void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
+ void generate_Increment() override;
+ void generate_Decrement() override;
+ void generate_Add(int lhs) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
@@ -197,10 +197,10 @@ public:
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
+ void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
+ void generate_Mod(int lhs) override;
+ void generate_Sub(int lhs) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
diff --git a/src/qml/jit/qv4blockscheduler.cpp b/src/qml/jit/qv4blockscheduler.cpp
deleted file mode 100644
index 3e2bfe15c5..0000000000
--- a/src/qml/jit/qv4blockscheduler.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4blockscheduler_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcBlockScheduler, "qt.v4.ir.blockscheduler")
-
-bool BlockScheduler::checkCandidate(MIBlock *candidate)
-{
- Q_ASSERT(loopInfo.loopHeaderFor(candidate) == currentGroup.group);
-
- for (MIBlock *pred : candidate->inEdges()) {
- if (pred->isDeoptBlock())
- continue;
-
- if (emitted.alreadyProcessed(pred))
- continue;
-
- if (dominatorTree.dominates(candidate->index(), pred->index())) {
- // this is a loop, where there in
- // -> candidate edge is the jump back to the top of the loop.
- continue;
- }
-
- if (pred == candidate)
- // this is a very tight loop, e.g.:
- // L1: ...
- // goto L1
- // This can happen when, for example, the basic-block merging gets rid of the empty
- // body block. In this case, we can safely schedule this block (if all other
- // incoming edges are either loop-back edges, or have been scheduled already).
- continue;
-
- return false; // an incoming edge that is not yet emitted, and is not a back-edge
- }
-
- if (loopInfo.isLoopHeader(candidate)) {
- // postpone everything, and schedule the loop first.
- postponedGroups.push(currentGroup);
- currentGroup = WorkForGroup(candidate);
- }
-
- return true;
-}
-
-MIBlock *BlockScheduler::pickNext()
-{
- while (true) {
- while (currentGroup.postponed.isEmpty()) {
- if (postponedGroups.isEmpty())
- return nullptr;
- if (currentGroup.group) // record the first and the last node of a group
- loopsStartEnd[currentGroup.group] = sequence.back();
- currentGroup = postponedGroups.pop();
- }
-
- MIBlock *next = currentGroup.postponed.pop();
- if (checkCandidate(next))
- return next;
- }
-
- Q_UNREACHABLE();
- return nullptr;
-}
-
-void BlockScheduler::emitBlock(MIBlock *bb)
-{
- if (emitted.alreadyProcessed(bb))
- return;
-
- sequence.push_back(bb);
- emitted.markAsProcessed(bb);
-}
-
-void BlockScheduler::schedule(MIBlock *functionEntryPoint)
-{
- MIBlock *next = functionEntryPoint;
-
- while (next) {
- emitBlock(next);
- // postpone all outgoing edges, if they were not already processed
- QVarLengthArray<MIBlock *, 32> nonExceptionEdges;
- // first postpone all exception edges, so they will be processed last
- for (int i = next->outEdges().size(); i != 0; ) {
- --i;
- MIBlock *out = next->outEdges().at(i);
- if (emitted.alreadyProcessed(out))
- continue;
- if (out == nullptr)
- continue;
- if (out->instructions().front().opcode() == Meta::OnException)
- postpone(out);
- else
- nonExceptionEdges.append(out);
- }
- for (MIBlock *edge : nonExceptionEdges)
- postpone(edge);
- next = pickNext();
- }
-
- // finally schedule all de-optimization blocks at the end
- for (auto bb : dominatorTree.function()->blocks()) {
- if (bb->isDeoptBlock())
- emitBlock(bb);
- }
-}
-
-void BlockScheduler::postpone(MIBlock *bb)
-{
- if (currentGroup.group == loopInfo.loopHeaderFor(bb)) {
- currentGroup.postponed.append(bb);
- return;
- }
-
- for (int i = postponedGroups.size(); i != 0; ) {
- --i;
- WorkForGroup &g = postponedGroups[i];
- if (g.group == loopInfo.loopHeaderFor(bb)) {
- g.postponed.append(bb);
- return;
- }
- }
-
- Q_UNREACHABLE();
-}
-
-void BlockScheduler::dump() const
-{
- if (!lcBlockScheduler().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Scheduled blocks:\n");
- for (auto *bb : sequence) {
- s += QLatin1String(" L") + QString::number(bb->index());
- MIBlock *loopEnd = loopsStartEnd[bb];
- if (loopEnd)
- s += QLatin1String(", loop start, ends at L") + QString::number(loopEnd->index());
- s += QLatin1Char('\n');
- }
- qCDebug(lcBlockScheduler).noquote().nospace() << s;
-}
-
-BlockScheduler::BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo)
- : dominatorTree(dominatorTree)
- , loopInfo(loopInfo)
- , sequence(0)
- , emitted(dominatorTree.function())
-{
- schedule(dominatorTree.function()->blocks().front());
-
- dump();
-
- if (dominatorTree.function()->blockCount() != sequence.size()) {
- qFatal("The block scheduler did not schedule all blocks. This is most likely due to"
- "a non-natural loop.");
- // Usually caused by having an execution path that manages to skip over unwind handler
- // reset: any exception happening after will jump back to the unwind handler, and thereby
- // creating a loop that can be entered in 2 different ways.
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4blockscheduler_p.h b/src/qml/jit/qv4blockscheduler_p.h
deleted file mode 100644
index 1289fda9f0..0000000000
--- a/src/qml/jit/qv4blockscheduler_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4BLOCKSCHEDULER_P_H
-#define QV4BLOCKSCHEDULER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qstack.h>
-
-#include "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-class LoopInfo;
-
-// High-level algorithm:
-// 0. start with the first node (the start node) of a function
-// 1. emit the node
-// 2. add all outgoing edges that are not yet emitted to the postponed stack
-// 3. When the postponed stack is empty, pop a stack from the loop stack. If that is empty too,
-// we're done.
-// 4. pop a node from the postponed stack, and check if it can be scheduled:
-// a. if all incoming edges are scheduled, go to 4.
-// b. if an incoming edge is unscheduled, but it's a back-edge (an edge in a loop that jumps
-// back to the start of the loop), ignore it
-// c. if there is any unscheduled edge that is not a back-edge, ignore this node, and go to 4.
-// 5. if this node is the start of a loop, push the postponed stack on the loop stack.
-// 6. go back to 1.
-//
-// The postponing action in step 2 will put the node into its containing group. The case where this
-// is important is when a (labeled) continue or a (labeled) break statement occur in a loop: the
-// outgoing edge points to a node that is not part of the current loop (and possibly not of the
-// parent loop).
-//
-// Linear scan register allocation benefits greatly from short life-time intervals with few holes
-// (see for example section 4 (Lifetime Analysis) of [Wimmer1]). This algorithm makes sure that the
-// blocks of a group are scheduled together, with no non-loop blocks in between. This applies
-// recursively for nested loops. It also schedules groups of if-then-else-endif blocks together for
-// the same reason.
-class BlockScheduler
-{
- const DominatorTree &dominatorTree;
- const LoopInfo &loopInfo;
-
- struct WorkForGroup
- {
- MIBlock *group;
- QStack<MIBlock *> postponed;
-
- WorkForGroup(MIBlock *group = nullptr) : group(group) {}
- };
- WorkForGroup currentGroup;
- QStack<WorkForGroup> postponedGroups;
- std::vector<MIBlock *> sequence;
-
- class ProcessedBlocks
- {
- BitVector processed;
-
- public:
- ProcessedBlocks(MIFunction *function)
- : processed(int(function->blockCount()), false)
- {}
-
- bool alreadyProcessed(MIBlock *bb) const
- {
- Q_ASSERT(bb);
-
- return processed.at(bb->index());
- }
-
- void markAsProcessed(MIBlock *bb)
- {
- processed.setBit(bb->index());
- }
- } emitted;
- QHash<MIBlock *, MIBlock *> loopsStartEnd;
-
- bool checkCandidate(MIBlock *candidate);
- MIBlock *pickNext();
- void emitBlock(MIBlock *bb);
- void schedule(MIBlock *functionEntryPoint);
- void postpone(MIBlock *bb);
- void dump() const;
-
-public:
- BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo);
-
- const std::vector<MIBlock *> &scheduledBlockSequence() const
- { return sequence; }
-
- QHash<MIBlock *, MIBlock *> loopEndsByStartBlock() const
- { return loopsStartEnd; }
-};
-
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4BLOCKSCHEDULER_P_H
diff --git a/src/qml/jit/qv4domtree.cpp b/src/qml/jit/qv4domtree.cpp
deleted file mode 100644
index 9484f4e2dc..0000000000
--- a/src/qml/jit/qv4domtree.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qbuffer.h>
-
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcDomTree, "qt.v4.ir.domTree")
-Q_LOGGING_CATEGORY(lcDomFrontier, "qt.v4.ir.domFrontier")
-
-DominatorTree::DominatorTree(MIFunction *f)
- : m_function(f)
- , m_data(new Data)
-{
- calculateIDoms();
- m_data.reset();
-}
-
-void DominatorTree::dumpImmediateDominators() const
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Immediate dominators for " << m_function->irFunction()->name() << ":" << endl;
- for (MIBlock *to : m_function->blocks()) {
- MIBlock::Index from = m_idom.at(to->index());
- if (from != MIBlock::InvalidIndex)
- qout << " " << from;
- else
- qout << " (none)";
- qout << " dominates " << to->index() << endl;
- }
- qCDebug(lcDomTree, "%s", buf.data().constData());
-}
-
-void DominatorTree::setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator)
-{
- if (m_idom.size() <= size_t(dominated))
- m_idom.resize(dominated + 1);
- m_idom[dominated] = dominator;
-}
-
-bool DominatorTree::dominates(MIBlock::Index dominator, MIBlock::Index dominated) const
-{
- // dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
- Q_ASSERT(dominated != MIBlock::InvalidIndex);
-
- if (dominator == dominated)
- return false;
-
- for (MIBlock::Index it = m_idom[dominated]; it != MIBlock::InvalidIndex; it = m_idom[it]) {
- if (it == dominator)
- return true;
- }
-
- return false;
-}
-
-// Calculate a depth-first iteration order on the nodes of the dominator tree.
-//
-// The order of the nodes in the vector is not the same as one where a recursive depth-first
-// iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth.
-// So for the:
-// 1 dominates 2
-// 2 dominates 3
-// 3 dominates 4
-// 2 dominates 5
-// the order will be:
-// 4, 3, 5, 2, 1
-// or:
-// 4, 5, 3, 2, 1
-// So the order of nodes on the same depth is undefined, but it will be after the nodes
-// they dominate, and before the nodes that dominate them.
-//
-// The reason for this order is that a proper DFS pre-/post-order would require inverting
-// the idom vector by either building a real tree datastructure or by searching the idoms
-// for siblings and children. Both have a higher time complexity than sorting by depth.
-std::vector<MIBlock *> DominatorTree::calculateDFNodeIterOrder() const
-{
- std::vector<int> depths = calculateNodeDepths();
- std::vector<MIBlock *> order = m_function->blocks();
- std::sort(order.begin(), order.end(), [&depths](MIBlock *one, MIBlock *two) -> bool {
- return depths.at(one->index()) > depths.at(two->index());
- });
- return order;
-}
-
-// Algorithm:
-// - for each node:
-// - get the depth of a node. If it's unknown (-1):
-// - get the depth of the immediate dominator.
-// - if that's unknown too, calculate it by calling calculateNodeDepth
-// - set the current node's depth to that of immediate dominator + 1
-std::vector<int> DominatorTree::calculateNodeDepths() const
-{
- std::vector<int> nodeDepths(size_t(m_function->blockCount()), -1);
- for (MIBlock *bb : m_function->blocks()) {
- int &bbDepth = nodeDepths[bb->index()];
- if (bbDepth == -1) {
- const int immDom = m_idom[bb->index()];
- if (immDom == -1) {
- // no immediate dominator, so it's either the start block, or an unreachable block
- bbDepth = 0;
- } else {
- int immDomDepth = nodeDepths[immDom];
- if (immDomDepth == -1)
- immDomDepth = calculateNodeDepth(immDom, nodeDepths);
- bbDepth = immDomDepth + 1;
- }
- }
- }
- return nodeDepths;
-}
-
-// Algorithm:
-// - search for the first dominator of a node that has a known depth. As all nodes are
-// reachable from the start node, and that node's depth is 0, this is finite.
-// - while doing that search, put all unknown nodes in the worklist
-// - pop all nodes from the worklist, and set their depth to the previous' (== dominating)
-// node's depth + 1
-// This way every node's depth is calculated once, and the complexity is O(n).
-int DominatorTree::calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const
-{
- std::vector<int> worklist;
- worklist.reserve(8);
- int depth = -1;
-
- do {
- worklist.push_back(nodeIdx);
- nodeIdx = m_idom[nodeIdx];
- depth = nodeDepths[nodeIdx];
- } while (depth == -1);
-
- for (auto it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it)
- nodeDepths[*it] = ++depth;
-
- return depth;
-}
-
-namespace {
-struct DFSTodo {
- MIBlock::Index node = MIBlock::InvalidIndex;
- MIBlock::Index parent = MIBlock::InvalidIndex;
-
- DFSTodo() = default;
- DFSTodo(MIBlock::Index node, MIBlock::Index parent)
- : node(node)
- , parent(parent)
- {}
-};
-} // anonymous namespace
-
-void DominatorTree::dfs(MIBlock::Index node)
-{
- std::vector<DFSTodo> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
- DFSTodo todo(node, MIBlock::InvalidIndex);
-
- while (true) {
- MIBlock::Index n = todo.node;
-
- if (m_data->dfnum[n] == 0) {
- m_data->dfnum[n] = m_data->size;
- m_data->vertex[m_data->size] = n;
- m_data->parent[n] = todo.parent;
- ++m_data->size;
-
- MIBlock::OutEdges out = m_function->block(n)->outEdges();
- for (int i = out.size() - 1; i > 0; --i)
- worklist.emplace_back(out[i]->index(), n);
-
- if (!out.isEmpty()) {
- todo.node = out.first()->index();
- todo.parent = n;
- continue;
- }
- }
-
- if (worklist.empty())
- break;
-
- todo = worklist.back();
- worklist.pop_back();
- }
-}
-
-void DominatorTree::link(MIBlock::Index p, MIBlock::Index n)
-{
- m_data->ancestor[n] = p;
- m_data->best[n] = n;
-}
-
-void DominatorTree::calculateIDoms()
-{
- Q_ASSERT(m_function->block(0)->inEdges().count() == 0);
-
- const size_t bbCount = m_function->blockCount();
- m_data->vertex = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->parent = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->dfnum = std::vector<unsigned>(bbCount, 0);
- m_data->semi = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->ancestor = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_idom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->samedom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->best = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
-
- QHash<MIBlock::Index, std::vector<MIBlock::Index>> bucket;
- bucket.reserve(int(bbCount));
-
- dfs(m_function->block(0)->index());
-
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
-
- for (int i = m_data->size - 1; i > 0; --i) {
- MIBlock::Index n = m_data->vertex[i];
- MIBlock::Index p = m_data->parent[n];
- MIBlock::Index s = p;
-
- for (auto inEdge : m_function->block(n)->inEdges()) {
- if (inEdge->isDeoptBlock())
- continue;
- MIBlock::Index v = inEdge->index();
- MIBlock::Index ss = MIBlock::InvalidIndex;
- if (m_data->dfnum[v] <= m_data->dfnum[n])
- ss = v;
- else
- ss = m_data->semi[ancestorWithLowestSemi(v, worklist)];
- if (m_data->dfnum[ss] < m_data->dfnum[s])
- s = ss;
- }
- m_data->semi[n] = s;
- bucket[s].push_back(n);
- link(p, n);
- if (bucket.contains(p)) {
- for (MIBlock::Index v : bucket[p]) {
- MIBlock::Index y = ancestorWithLowestSemi(v, worklist);
- MIBlock::Index semi_v = m_data->semi[v];
- if (m_data->semi[y] == semi_v)
- m_idom[v] = semi_v;
- else
- m_data->samedom[v] = y;
- }
- bucket.remove(p);
- }
- }
-
- for (unsigned i = 1; i < m_data->size; ++i) {
- MIBlock::Index n = m_data->vertex[i];
- Q_ASSERT(n != MIBlock::InvalidIndex);
- Q_ASSERT(!bucket.contains(n));
- Q_ASSERT(m_data->ancestor[n] != MIBlock::InvalidIndex);
- Q_ASSERT((m_data->semi[n] != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->ancestor[n]] <= m_data->dfnum[m_data->semi[n]])
- || m_data->semi[n] == n);
- MIBlock::Index sdn = m_data->samedom[n];
- if (sdn != MIBlock::InvalidIndex)
- m_idom[n] = m_idom[sdn];
- }
-
- if (lcDomTree().isDebugEnabled())
- dumpImmediateDominators();
-
- m_data.reset(nullptr);
-}
-
-MIBlock::Index DominatorTree::ancestorWithLowestSemi(MIBlock::Index v,
- std::vector<MIBlock::Index> &worklist)
-{
- worklist.clear();
- for (MIBlock::Index it = v; it != MIBlock::InvalidIndex; it = m_data->ancestor[it])
- worklist.push_back(it);
-
- if (worklist.size() < 2)
- return m_data->best[v];
-
- MIBlock::Index b = MIBlock::InvalidIndex;
- MIBlock::Index last = worklist.back();
- Q_ASSERT(worklist.size() <= INT_MAX);
- for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) {
- MIBlock::Index bbIt = worklist[it];
- m_data->ancestor[bbIt] = last;
- MIBlock::Index &best_it = m_data->best[bbIt];
- if (b != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->semi[b]] < m_data->dfnum[m_data->semi[best_it]]) {
- best_it = b;
- } else {
- b = best_it;
- }
- }
- return b;
-}
-
-void DominatorFrontier::compute(const DominatorTree &domTree)
-{
- struct NodeProgress {
- std::vector<MIBlock::Index> children;
- std::vector<MIBlock::Index> todo;
- };
-
- MIFunction *function = domTree.function();
- m_df.resize(function->blockCount());
-
- // compute children of each node in the dominator tree
- std::vector<std::vector<MIBlock::Index> > children; // BasicBlock index -> children
- children.resize(function->blockCount());
- for (MIBlock *n : function->blocks()) {
- const MIBlock::Index nodeIndex = n->index();
- Q_ASSERT(function->block(nodeIndex) == n);
- const MIBlock::Index nodeDominator = domTree.immediateDominator(nodeIndex);
- if (nodeDominator == MIBlock::InvalidIndex)
- continue; // there is no dominator to add this node to as a child (e.g. the start node)
- children[nodeDominator].push_back(nodeIndex);
- }
-
- // Fill the worklist and initialize the node status for each basic-block
- std::vector<NodeProgress> nodeStatus;
- nodeStatus.resize(function->blockCount());
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(function->blockCount());
- for (MIBlock *bb : function->blocks()) {
- MIBlock::Index nodeIndex = bb->index();
- worklist.push_back(nodeIndex);
- NodeProgress &np = nodeStatus[nodeIndex];
- np.children = children[nodeIndex];
- np.todo = children[nodeIndex];
- }
-
- BitVector DF_done(int(function->blockCount()), false);
-
- while (!worklist.empty()) {
- MIBlock::Index node = worklist.back();
-
- if (DF_done.at(node)) {
- worklist.pop_back();
- continue;
- }
-
- NodeProgress &np = nodeStatus[node];
- auto it = np.todo.begin();
- while (it != np.todo.end()) {
- if (DF_done.at(*it)) {
- it = np.todo.erase(it);
- } else {
- worklist.push_back(*it);
- break;
- }
- }
-
- if (np.todo.empty()) {
- MIBlockSet &miBlockSet = m_df[node];
- miBlockSet.init(function);
- for (MIBlock *y : function->block(node)->outEdges()) {
- if (domTree.immediateDominator(y->index()) != node)
- miBlockSet.insert(y);
- }
- for (MIBlock::Index child : np.children) {
- const MIBlockSet &ws = m_df[child];
- for (auto w : ws) {
- const MIBlock::Index wIndex = w->index();
- if (node == wIndex || !domTree.dominates(node, w->index()))
- miBlockSet.insert(w);
- }
- }
- DF_done.setBit(node);
- worklist.pop_back();
- }
- }
-
- if (lcDomFrontier().isDebugEnabled())
- dump(domTree.function());
-}
-
-void DominatorFrontier::dump(MIFunction *function)
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Dominator Frontiers:" << endl;
- for (MIBlock *n : function->blocks()) {
- qout << "\tDF[" << n->index() << "]: {";
- const MIBlockSet &SList = m_df[n->index()];
- for (MIBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) {
- if (i != SList.begin())
- qout << ", ";
- qout << (*i)->index();
- }
- qout << "}" << endl;
- }
- qCDebug(lcDomFrontier, "%s", buf.data().constData());
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4domtree_p.h b/src/qml/jit/qv4domtree_p.h
deleted file mode 100644
index 703e17ab61..0000000000
--- a/src/qml/jit/qv4domtree_p.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4DOMTREE_P_H
-#define QV4DOMTREE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-#include "qv4miblockset_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree
-{
- Q_DISABLE_COPY_MOVE(DominatorTree)
-
-public:
- DominatorTree(MIFunction *f);
- ~DominatorTree() = default;
-
- void dumpImmediateDominators() const;
- MIFunction *function() const
- { return m_function; }
-
- void setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator);
-
- MIBlock::Index immediateDominator(MIBlock::Index blockIndex) const
- { return m_idom[blockIndex]; }
-
- bool dominates(MIBlock::Index dominator, MIBlock::Index dominated) const;
-
- bool insideSameDominatorChain(MIBlock::Index one, MIBlock::Index other) const
- { return one == other || dominates(one, other) || dominates(other, one); }
-
- std::vector<MIBlock *> calculateDFNodeIterOrder() const;
-
- std::vector<int> calculateNodeDepths() const;
-
-private: // functions
- int calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const;
- void link(MIBlock::Index p, MIBlock::Index n);
- void calculateIDoms();
- void dfs(MIBlock::Index node);
- MIBlock::Index ancestorWithLowestSemi(MIBlock::Index v, std::vector<MIBlock::Index> &worklist);
-
-private: // data
- struct Data {
- std::vector<unsigned> dfnum; // MIBlock index -> dfnum
- std::vector<MIBlock::Index> vertex;
- std::vector<MIBlock::Index> parent; // MIBlock index -> parent MIBlock index
- std::vector<MIBlock::Index> ancestor; // MIBlock index -> ancestor MIBlock index
- std::vector<MIBlock::Index> best; // MIBlock index -> best MIBlock index
- std::vector<MIBlock::Index> semi; // MIBlock index -> semi dominator MIBlock index
- std::vector<MIBlock::Index> samedom; // MIBlock index -> same dominator MIBlock index
- unsigned size = 0;
- };
-
- MIFunction *m_function;
- QScopedPointer<Data> m_data;
- std::vector<MIBlock::Index> m_idom; // MIBlock index -> immediate dominator MIBlock index
-};
-
-class DominatorFrontier
-{
-public:
- DominatorFrontier(const DominatorTree &domTree)
- { compute(domTree); }
-
- const MIBlockSet &operator[](MIBlock *n) const
- { return m_df[n->index()]; }
-
-private: // functions
- void compute(const DominatorTree &domTree);
- void dump(MIFunction *function);
-
-private: // data
- std::vector<MIBlockSet> m_df; // MIBlock index -> dominator frontier
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4DOMTREE_P_H
diff --git a/src/qml/jit/qv4graph.cpp b/src/qml/jit/qv4graph.cpp
deleted file mode 100644
index 4025ceb993..0000000000
--- a/src/qml/jit/qv4graph.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4graph_p.h"
-#include "qv4operation_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Graph *Graph::create(Function *function)
-{
- auto storage = function->pool()->allocate(sizeof(Graph));
- auto g = new (storage) Graph(function);
- g->m_undefinedNode = g->createNode(g->opBuilder()->get<Meta::Undefined>());
- g->m_emptyNode = g->createNode(g->opBuilder()->get<Meta::Empty>());
- g->m_nullNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::nullValue()));
- g->m_trueNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(true)));
- g->m_falseNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(false)));
- return g;
-}
-
-Graph::MemoryPool *Graph::pool() const
-{
- return m_function->pool();
-}
-
-Node *Graph::createNode(const Operation *op, Node *const operands[], size_t opCount,
- bool incomplete)
-{
- return Node::create(pool(), m_nextNodeId++, op, opCount, operands, incomplete);
-}
-
-Node *Graph::createConstantBoolNode(bool value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromBoolean(value)));
-}
-
-Node *Graph::createConstantIntNode(int value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromInt32(value)));
-}
-
-Graph::Graph(Function *function)
- : m_function(function)
- , m_opBuilder(OperationBuilder::create(pool()))
-{}
-
-Node *Graph::createConstantHeapNode(Heap::Base *heap)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromHeapObject(heap)));
-}
-
-void Graph::addEndInput(Node *n)
-{
- if (m_endNode) {
- auto newEnd = m_opBuilder->getEnd(m_endNode->operation()->controlInputCount() + 1);
- m_endNode->setOperation(newEnd);
- m_endNode->addInput(m_function->pool(), n);
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graph_p.h b/src/qml/jit/qv4graph_p.h
deleted file mode 100644
index 4706399c94..0000000000
--- a/src/qml/jit/qv4graph_p.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPH_P_H
-#define QV4GRAPH_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4node_p.h>
-
-#include <array>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Function;
-class Operation;
-class OperationBuilder;
-
-class Graph final
-{
- Q_DISABLE_COPY_MOVE(Graph)
-
-public:
- using MemoryPool = QQmlJS::MemoryPool;
-
-public:
- static Graph *create(Function *function);
- ~Graph() = delete;
-
- MemoryPool *pool() const;
- OperationBuilder *opBuilder() const
- { return m_opBuilder; }
-
- Node *createNode(const Operation *op, Node * const operands[] = nullptr, size_t opCount = 0,
- bool incomplete = false);
- template <typename... Nodes>
- Node *createNode(Operation *op, Nodes*... nodes) {
- std::array<Node *, sizeof...(nodes)> nodesArray {{ nodes... }};
- return createNode(op, nodesArray.data(), nodesArray.size());
- }
- Node *createConstantBoolNode(bool value);
- Node *createConstantIntNode(int value);
- Node *createConstantHeapNode(Heap::Base *heap);
-
- Node *undefinedNode() const { return m_undefinedNode; }
- Node *emptyNode() const { return m_emptyNode; }
- Node *nullNode() const { return m_nullNode; }
- Node *trueConstant() const { return m_trueNode; }
- Node *falseConstant() const { return m_falseNode; }
-
- Node *startNode() const { return m_startNode; }
- Node *engineNode() const { return m_engineNode; }
- Node *functionNode() const { return m_functionNode; }
- Node *cppFrameNode() const { return m_cppFrameNode; }
- Node *endNode() const { return m_endNode; }
- Node *initialFrameState() const { return m_initialFrameState; }
- void setStartNode(Node *n) { m_startNode = n; }
- void setEngineNode(Node *n) { m_engineNode = n; }
- void setFunctionNode(Node *n) { m_functionNode = n; }
- void setCppFrameNode(Node *n) { m_cppFrameNode = n; }
- void setEndNode(Node *n) { m_endNode = n; }
- void setInitialFrameState(Node *n) { m_initialFrameState = n; }
-
- unsigned nodeCount() const
- { return unsigned(m_nextNodeId); }
-
- void addEndInput(Node *n);
-
-private: // types and methods
- Graph(Function *function);
-
-private: // fields
- Function *m_function;
- OperationBuilder *m_opBuilder;
- Node::Id m_nextNodeId = 0;
- Node *m_undefinedNode = nullptr;
- Node *m_emptyNode = nullptr;
- Node *m_nullNode = nullptr;
- Node *m_trueNode = nullptr;
- Node *m_falseNode = nullptr;
- Node *m_startNode = nullptr;
- Node *m_engineNode = nullptr;
- Node *m_functionNode = nullptr;
- Node *m_cppFrameNode = nullptr;
- Node *m_endNode = nullptr;
- Node *m_initialFrameState = nullptr;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPH_P_H
diff --git a/src/qml/jit/qv4graphbuilder.cpp b/src/qml/jit/qv4graphbuilder.cpp
deleted file mode 100644
index 2c073701ee..0000000000
--- a/src/qml/jit/qv4graphbuilder.cpp
+++ /dev/null
@@ -1,1683 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4graphbuilder_p.h"
-#include "qv4function_p.h"
-#include "qv4lookup_p.h"
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcIRGraphBuilder, "qt.v4.ir.graphbuilder")
-
-using MemoryPool = QQmlJS::MemoryPool;
-
-namespace {
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-
-template <typename Array>
-inline size_t arraySize(const Array &array)
-{
- Q_UNUSED(array); // for MSVC
- return sizeof(ArraySizeHelper(array));
-}
-} // anonymous namespace
-
-class GraphBuilder::InterpreterEnvironment
-{
-public:
- struct FrameState: public QQmlJS::FixedPoolArray<Node *>
- {
- FrameState(MemoryPool *pool, int totalSlotCount)
- : FixedPoolArray(pool, totalSlotCount)
- {}
-
- Node *&unwindHandlerOffset()
- { return at(size() - 1); }
-
- static FrameState *create(MemoryPool *pool, int jsSlotCount)
- {
- auto totalSlotCount = jsSlotCount;
- auto fs = pool->New<FrameState>(pool, totalSlotCount);
- return fs;
- }
-
- static FrameState *clone(MemoryPool *pool, FrameState *other)
- {
- FrameState *fs = create(pool, other->size());
-
- for (int i = 0, ei = other->size(); i != ei; ++i)
- fs->at(i) = other->at(i);
-
- return fs;
- }
- };
-
-public:
- InterpreterEnvironment(GraphBuilder *graphBuilder, Node *controlDependency)
- : m_graphBuilder(graphBuilder)
- , m_effectDependency(controlDependency)
- , m_controlDependency(controlDependency)
- , m_currentFrame(nullptr)
- {}
-
- void createEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- // 1 extra slot for the unwindHandlerOffset
- m_currentFrame = FrameState::create(graph()->pool(), int(nRegisters + 1));
- }
-
- void setupStartEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nFormals = v4Function->compiledFunction->nFormals;
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- createEnvironment();
-
- Node *startNode = graph()->startNode();
- auto opB = opBuilder();
- auto create = [&](int index, const char *name) {
- m_currentFrame->at(index) = graph()->createNode(
- opB->getParam(index, f->addString(QLatin1String(name))), startNode);
- };
- create(0, "%function");
- create(1, "%context");
- create(2, "%acc");
- create(3, "%this");
- create(4, "%newTarget");
- create(5, "%argc");
- const quint32_le *formalNameIdx = v4Function->compiledFunction->formalsTable();
- for (size_t i = 0; i < nFormals; ++i, ++formalNameIdx) {
- const int slot = int(CallData::HeaderSize() + i);
- Q_ASSERT(*formalNameIdx <= quint32(std::numeric_limits<int>::max()));
- auto op = opB->getParam(
- slot,
- f->addString(v4Function->compilationUnit->stringAt(int(*formalNameIdx))));
- Node *argNode = graph()->createNode(op, startNode);
- m_currentFrame->at(slot) = argNode;
- }
- Node *undefinedNode = graph()->undefinedNode();
- Node *emptyNode = graph()->emptyNode();
- const auto firstDeadZoneRegister
- = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
- const auto registerDeadZoneSize
- = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
- for (size_t i = CallData::HeaderSize() + nFormals; i < nRegisters; ++i) {
- const bool isDead = i >= firstDeadZoneRegister
- && i < size_t(firstDeadZoneRegister + registerDeadZoneSize);
- m_currentFrame->at(int(i)) = isDead ? emptyNode : undefinedNode;
- }
- setUnwindHandlerOffset(0);
- }
-
- Function *function() const { return m_graphBuilder->function(); }
- Graph *graph() const { return function()->graph(); }
- OperationBuilder *opBuilder() const { return graph()->opBuilder(); }
- GraphBuilder *graphBuilder() const { return m_graphBuilder; }
-
- Node *bindAcc(Node *node)
- {
- bindNodeToSlot(node, CallData::Accumulator);
- return node;
- }
-
- Node *accumulator() const
- { return slot(CallData::Accumulator); }
-
- Node *bindNodeToSlot(Node *node, int slot)
- {
- m_currentFrame->at(size_t(slot)) = node;
- return node;
- }
-
- Node *slot(int slot) const
- { return m_currentFrame->at(slot); }
-
- int slotCount() const
- { return m_currentFrame->size(); }
-
- Node *effectDependency() const
- { return m_effectDependency; }
-
- void setEffectDependency(Node *newNode)
- { m_effectDependency = newNode; }
-
- Node *controlDependency() const
- { return m_controlDependency; }
-
- void setControlDependency(Node *newNode)
- { m_controlDependency = newNode; }
-
- Node *createFrameState()
- {
- return graph()->createNode(graphBuilder()->opBuilder()->getFrameState(slotCount()),
- m_currentFrame->begin(), slotCount());
- }
-
- Node *merge(InterpreterEnvironment *other);
-
- InterpreterEnvironment *copy() const
- {
- auto *newEnv = graph()->pool()->New<InterpreterEnvironment>(graphBuilder(),
- controlDependency());
- newEnv->setEffectDependency(effectDependency());
- newEnv->m_currentFrame = FrameState::clone(graph()->pool(), m_currentFrame);
- return newEnv;
- }
-
- int unwindHandlerOffset() const
- {
- auto uhOp = m_currentFrame->unwindHandlerOffset()->operation();
- Q_ASSERT(uhOp->kind() == Meta::Constant);
- return ConstantPayload::get(*uhOp)->value().int_32();
- }
-
- void setUnwindHandlerOffset(int newOffset)
- { m_currentFrame->unwindHandlerOffset() = graphBuilder()->createConstant(newOffset); }
-
- FrameState *frameState() const
- { return m_currentFrame; }
-
-private:
- GraphBuilder *m_graphBuilder;
- Node *m_effectDependency;
- Node *m_controlDependency;
- FrameState *m_currentFrame;
-};
-
-namespace {
-class InterpreterSubEnvironment final
-{
- Q_DISABLE_COPY_MOVE(InterpreterSubEnvironment)
-
-public:
- explicit InterpreterSubEnvironment(GraphBuilder *builder)
- : m_builder(builder)
- , m_parent(builder->env()->copy())
- {}
-
- ~InterpreterSubEnvironment()
- { m_builder->setEnv(m_parent); }
-
-private:
- GraphBuilder *m_builder;
- GraphBuilder::InterpreterEnvironment *m_parent;
-};
-} // anonymous namespace
-
-Node *GraphBuilder::InterpreterEnvironment::merge(InterpreterEnvironment *other)
-{
- Q_ASSERT(m_currentFrame->size() == other->m_currentFrame->size());
-
- auto gb = graphBuilder();
- Node *mergedControl = gb->mergeControl(controlDependency(), other->controlDependency());
- setControlDependency(mergedControl);
- setEffectDependency(gb->mergeEffect(effectDependency(), other->effectDependency(), mergedControl));
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = m_currentFrame->size() - 1; i != ei; ++i) {
- //### use lifeness info to trim this!
- m_currentFrame->at(i) = gb->mergeValue(m_currentFrame->at(i),
- other->m_currentFrame->at(i),
- mergedControl);
- }
- Q_ASSERT(unwindHandlerOffset() >= 0); // specifically: don't crash
- return mergedControl;
-}
-
-void GraphBuilder::buildGraph(IR::Function *function)
-{
- const char *code = function->v4Function()->codeData;
- uint len = function->v4Function()->compiledFunction->codeSize;
-
- GraphBuilder builder(function);
- builder.startGraph();
-
- InterpreterEnvironment initial(&builder, function->graph()->startNode());
- initial.setupStartEnvironment();
- builder.setEnv(&initial);
- builder.graph()->setInitialFrameState(initial.createFrameState());
- builder.decode(code, len);
- builder.endGraph();
-};
-
-GraphBuilder::GraphBuilder(IR::Function *function)
- : m_func(function)
- , m_graph(function->graph())
- , m_currentEnv(nullptr)
-{
- for (unsigned i = 0, ei = m_func->v4Function()->compiledFunction->nLabelInfos; i != ei; ++i) {
- unsigned label = m_func->v4Function()->compiledFunction->labelInfoTable()[i];
- m_labelInfos.emplace_back(label);
- if (lcIRGraphBuilder().isDebugEnabled()) {
- const LabelInfo &li = m_labelInfos.back();
- qCDebug(lcIRGraphBuilder) << "Loop start at" << li.labelOffset;
- }
- }
-}
-
-void GraphBuilder::startGraph()
-{
- size_t nValuesOut = 1 + CallData::HeaderSize()
- + m_func->v4Function()->compiledFunction->nFormals;
- Node *start = m_graph->createNode(opBuilder()->getStart(uint16_t(nValuesOut)), nullptr, 0);
- m_func->nodeInfo(start)->setBytecodeOffsets(0, 0);
- m_graph->setStartNode(start);
- m_graph->setEngineNode(m_graph->createNode(opBuilder()->get<Meta::Engine>(), &start, 1));
- auto frame = m_graph->createNode(opBuilder()->get<Meta::CppFrame>(), &start, 1);
- m_graph->setCppFrameNode(frame);
- m_graph->setFunctionNode(m_graph->createNode(opBuilder()->get<Meta::Function>(),
- &frame, 1));
-}
-
-void GraphBuilder::endGraph()
-{
- const auto inputCount = uint16_t(m_exitControls.size());
- Node **inputs = &m_exitControls.front();
- Q_ASSERT(m_graph->endNode() == nullptr);
- m_graph->setEndNode(m_graph->createNode(opBuilder()->getEnd(inputCount), inputs, inputCount));
-}
-
-Node *GraphBuilder::bindAcc(Node *n)
-{
- return env()->bindAcc(n);
-}
-
-/* IMPORTANT!!!
- *
- * This might change the success environment, so don't call:
- * env()->bindAcc(createNode(...))
- * because the binding should only happen on success, but the call to env() will get the
- * environment from *before* the new success environment was created. Instead, do:
- * bindAcc(createNode(....))
- */
-Node *GraphBuilder::createAndLinkNode(Operation *op, Node *operands[], size_t opCount,
- bool incomplete)
-{
- Q_ASSERT(op->effectInputCount() < 2);
- Q_ASSERT(op->controlInputCount() < 2);
-
- QVarLengthArray<Node *, 32> inputs(static_cast<int>(opCount));
- std::copy_n(operands, opCount, inputs.data());
-
- if (op->effectInputCount() == 1)
- inputs.append(env()->effectDependency());
- if (op->controlInputCount() == 1)
- inputs.append(env()->controlDependency());
- if (op->hasFrameStateInput())
- inputs.append(env()->createFrameState());
-
- Node *node = m_graph->createNode(op, inputs.data(), inputs.size(), incomplete);
-
- if (op->needsBytecodeOffsets()) {
- m_func->nodeInfo(node)->setBytecodeOffsets(currentInstructionOffset(),
- nextInstructionOffset());
- }
-
- if (op->effectOutputCount() > 0)
- env()->setEffectDependency(node);
- if (op->controlOutputCount() > 0)
- env()->setControlDependency(node);
-
- if (op->canThrow() && env()->unwindHandlerOffset()) {
- InterpreterSubEnvironment successEnv(this);
- Node *control = env()->controlDependency();
- control = m_graph->createNode(opBuilder()->get<Meta::OnException>(), &control, 1);
- env()->setControlDependency(control);
- auto unwindHandlerOffset = env()->unwindHandlerOffset();
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- return node;
-}
-
-Node *GraphBuilder::createNode(Operation *op, bool incomplete)
-{
- return createAndLinkNode(op, nullptr, 0, incomplete);
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1)
-{
- Node *buf[] = { n1 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2)
-{
- Node *buf[] = { n1, n2 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3)
-{
- Node *buf[] = { n1, n2, n3 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4)
-{
- Node *buf[] = { n1, n2, n3, n4 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createRegion(unsigned nControlInputs)
-{
- return createNode(opBuilder()->getRegion(nControlInputs), true);
-}
-
-Node *GraphBuilder::createIfTrue()
-{
- return createNode(opBuilder()->get<Meta::IfTrue>());
-}
-
-Node *GraphBuilder::createIfFalse()
-{
- return createNode(opBuilder()->get<Meta::IfFalse>());
-}
-
-Node *GraphBuilder::createConstant(int v)
-{
- return m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(v)));
-}
-
-Node *GraphBuilder::createPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createEffectPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getEffectPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createHandleUnwind(int offset)
-{
- return createNode(opBuilder()->getHandleUnwind(offset));
-}
-
-Node *GraphBuilder::mergeControl(Node *c1, Node *c2)
-{
- if (c1->operation()->kind() == Meta::Region) {
- const unsigned nInputs = c1->operation()->controlInputCount() + 1;
- c1->addInput(m_graph->pool(), c2);
- c1->setOperation(opBuilder()->getRegion(nInputs));
- return c1;
- }
- auto op = opBuilder()->getRegion(2);
- Node *inputs[] = { c1, c2 };
- return m_graph->createNode(op, inputs, 2);
-}
-
-Node *GraphBuilder::mergeEffect(Node *e1, Node *e2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (e1->operation()->kind() == Meta::EffectPhi && e1->controlInput() == control) {
- e1->insertInput(m_graph->pool(), nInputs - 1, e2);
- e1->setOperation(opBuilder()->getEffectPhi(nInputs));
- return e1;
- }
-
- if (e1 != e2) {
- Node *phi = createEffectPhi(nInputs, e1, control);
- phi->replaceInput(nInputs - 1, e2);
- return phi;
- }
-
- return e1;
-}
-
-Node *GraphBuilder::mergeValue(Node *v1, Node *v2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (v1->operation()->kind() == Meta::Phi && v1->controlInput() == control) {
- v1->insertInput(m_graph->pool(), nInputs - 1, v2);
- v1->setOperation(opBuilder()->getPhi(nInputs));
- return v1;
- }
-
- if (v1 != v2) {
- Node *phi = createPhi(nInputs, v1, control);
- phi->replaceInput(nInputs - 1, v2);
- return phi;
- }
-
- return v1;
-}
-
-Node *GraphBuilder::createToBoolean(Node *input)
-{
- return createNode(opBuilder()->get<Meta::ToBoolean>(), input);
-}
-
-void GraphBuilder::populate(VarArgNodes &args, int argc, int argv)
-{
- for (int i = 0; i < argc; ++i)
- args.append(env()->slot(argv + i));
- Q_ASSERT(argc >= 0 && argc <= std::numeric_limits<uint16_t>::max());
-}
-
-void GraphBuilder::queueFunctionExit(Node *exitNode)
-{
- m_exitControls.push_back(exitNode);
- setEnv(nullptr);
-}
-
-Node *GraphBuilder::mergeIntoSuccessor(int offset)
-{
- InterpreterEnvironment *&successorEnvironment = m_envForOffset[offset];
-
- Node *region = nullptr;
- if (successorEnvironment == nullptr) {
- region = createRegion(1);
- successorEnvironment = env();
- } else {
- // Merge any values which are live coming into the successor.
- region = successorEnvironment->merge(env());
- }
- setEnv(nullptr);
- return region;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::labelInfoAt(unsigned offset) const
-{
- for (const LabelInfo &li : m_labelInfos) {
- if (li.labelOffset == offset)
- return &li;
- }
- return nullptr;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::isLoopStart(unsigned offset) const
-{
- if (auto li = labelInfoAt(offset)) {
- //### in the future, check if this is a loop start, or some other label
- return li;
- }
-
- return nullptr;
-}
-
-void GraphBuilder::handleLoopStart(const LabelInfo &labelInfo)
-{
- Q_ASSERT(env() != nullptr);
-
- // We unconditionally insert a region node with phi nodes here. Now there might already be
- // such a node, (e.g. the region after an if-then-else), but for simplicity we ignore that.
- // A subsequent pass will fold/remove chains of Region nodes.
- //### FIXME: add a DCE pass
-
- const auto offset = int(labelInfo.labelOffset);
- Node *control = createRegion(1);
- env()->setControlDependency(control);
- Node *effect = createEffectPhi(1, env()->effectDependency(), control);
- env()->setEffectDependency(effect);
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = env()->slotCount() - 1; i != ei; ++i) {
- //### use lifeness info to trim this further!
- if (i == CallData::Accumulator)
- continue; // should never be alive on loop entry
- env()->bindNodeToSlot(createPhi(1, env()->slot(i), control), i);
- }
-
- m_envForOffset.insert(offset, env()->copy());
-}
-
-void GraphBuilder::startUnwinding()
-{
- if (int target = env()->unwindHandlerOffset()) {
- mergeIntoSuccessor(target);
- } else {
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
-}
-
-void GraphBuilder::generate_Ret()
-{
- Node* control = createNode(opBuilder()->get<Meta::Return>(), env()->accumulator());
- queueFunctionExit(control);
-}
-
-void GraphBuilder::generate_Debug() { Q_UNREACHABLE(); }
-
-void GraphBuilder::generate_LoadConst(int index)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadZero()
-{
- bindAcc(createConstant(0));
-}
-
-void GraphBuilder::generate_LoadTrue()
-{
- bindAcc(m_graph->trueConstant());
-}
-
-void GraphBuilder::generate_LoadFalse()
-{
- bindAcc(m_graph->falseConstant());
-}
-
-void GraphBuilder::generate_LoadNull()
-{
- bindAcc(m_graph->nullNode());
-}
-
-void GraphBuilder::generate_LoadUndefined()
-{
- bindAcc(m_graph->undefinedNode());
-}
-
-void GraphBuilder::generate_LoadInt(int value)
-{
- bindAcc(m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(value))));
-}
-
-void GraphBuilder::generate_MoveConst(int constIndex, int destTemp)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[constIndex];
- env()->bindNodeToSlot(createNode(opBuilder()->getConstant(v)), destTemp);
-}
-
-void GraphBuilder::generate_LoadReg(int reg)
-{
- bindAcc(env()->slot(reg));
-}
-
-void GraphBuilder::generate_StoreReg(int reg)
-{
- Node *n = env()->accumulator();
- if (reg == CallData::This)
- n = createNode(opBuilder()->get<Meta::StoreThis>(), n);
- env()->bindNodeToSlot(n, reg);
-}
-
-void GraphBuilder::generate_MoveReg(int srcReg, int destReg)
-{
- env()->bindNodeToSlot(env()->slot(srcReg), destReg);
-}
-
-void GraphBuilder::generate_LoadImport(int index)
-{
- auto func = function()->v4Function();
- Value v = *func->compilationUnit->imports[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadLocal(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(0),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreLocal(int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(0),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(scope),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreScopedLocal(int scope, int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(scope),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadRuntimeString(int stringId)
-{
- auto func = function()->v4Function();
- Value v = Value::fromHeapObject(func->compilationUnit->runtimeStrings[stringId]);
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_MoveRegExp(int regExpId, int destReg)
-{
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::LoadRegExp>(),
- createConstant(regExpId)), destReg);
-}
-
-void GraphBuilder::generate_LoadClosure(int value)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadClosure>(),
- createConstant(value)));
-}
-
-void GraphBuilder::generate_LoadName(int name, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadGlobalLookup>(), createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreNameSloppy(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameSloppy>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_StoreNameStrict(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameStrict>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadElement(int base, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadElement>(),
- env()->slot(base),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_StoreElement(int base, int index, int /*traceSlot*/)
-{
- createNode(opBuilder()->get<Meta::JSStoreElement>(),
- env()->slot(base),
- env()->slot(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadProperty(int name, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSLoadProperty>(),
- env()->accumulator(),
- createConstant(name));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_GetLookup(int index, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSGetLookup>(),
- env()->accumulator(),
- createConstant(index));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_StoreProperty(int name, int base)
-{
- createNode(opBuilder()->get<Meta::JSStoreProperty>(),
- env()->slot(base),
- createConstant(name),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_SetLookup(int index, int base)
-{
-
- function()->v4Function()->isStrict()
- ? createNode(opBuilder()->get<Meta::JSSetLookupStrict>(), env()->slot(base),
- createConstant(index), env()->accumulator())
- : createNode(opBuilder()->get<Meta::JSSetLookupSloppy>(), env()->slot(base),
- createConstant(index), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadSuperProperty(int property)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperProperty>(),
- env()->slot(property)));
-}
-
-void GraphBuilder::generate_StoreSuperProperty(int property)
-{
- createNode(opBuilder()->get<Meta::JSStoreSuperProperty>(),
- createConstant(property),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadQmlContextPropertyLookup(int propertyIndex, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::QMLLoadQmlContextPropertyLookup>(),
- createConstant(propertyIndex)));
-}
-
-void GraphBuilder::generate_Yield() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_YieldStar() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_Resume(int /*offset*/) { Q_UNREACHABLE(); }
-
-void GraphBuilder::finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv)
-{
- populate(args, argc, argv);
- bindAcc(createAndLinkNode(opBuilder()->getJSVarArgsCall(kind, uint16_t(args.size())),
- args.data(), size_t(args.size())));
-}
-
-void GraphBuilder::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- finalizeCall(Meta::JSCallValue, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithReceiver, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallProperty, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(lookupIndex));
- finalizeCall(Meta::JSCallLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(env()->slot(index));
- finalizeCall(Meta::JSCallElement, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallName, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSCallPossiblyDirectEval, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::JSCallGlobalLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::QMLCallQmlContextPropertyLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_SetUnwindHandler(int offset)
-{
- m_currentUnwindHandlerOffset = offset ? absoluteOffset(offset) : 0;
- env()->setUnwindHandlerOffset(m_currentUnwindHandlerOffset);
-}
-
-void GraphBuilder::generate_UnwindDispatch()
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
- {
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- startUnwinding();
- }
-
- createIfFalse();
-
- const auto unwindHandlerOffset = env()->unwindHandlerOffset();
- const auto fallthroughSuccessor = nextInstructionOffset();
- auto nContinuations = m_func->unwindLabelOffsets().size() + 1;
- if (unwindHandlerOffset)
- ++nContinuations;
- Q_ASSERT(nContinuations <= std::numeric_limits<unsigned>::max());
- createNode(opBuilder()->getUnwindDispatch(unsigned(nContinuations), unwindHandlerOffset,
- fallthroughSuccessor));
-
- {
- InterpreterSubEnvironment fallthroughEnv(this);
- mergeIntoSuccessor(fallthroughSuccessor);
- }
-
- if (unwindHandlerOffset) {
- InterpreterSubEnvironment unwindHandlerEnv(this);
- createHandleUnwind(unwindHandlerOffset);
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- for (int unwindLabelOffset : m_func->unwindLabelOffsets()) {
- if (unwindLabelOffset <= currentInstructionOffset())
- continue;
- InterpreterSubEnvironment unwindLabelEnv(this);
- createHandleUnwind(unwindLabelOffset);
- mergeIntoSuccessor(unwindLabelOffset);
- }
-
- setEnv(nullptr);
-}
-
-void GraphBuilder::generate_UnwindToLabel(int level, int offset)
-{
- //### For de-optimization, the relative offset probably also needs to be stored
- int unwinder = absoluteOffset(offset);
- createNode(opBuilder()->get<Meta::UnwindToLabel>(),
- createConstant(level),
- createConstant(unwinder));
- m_func->addUnwindLabelOffset(unwinder);
- startUnwinding();
-}
-
-void GraphBuilder::generate_DeadTemporalZoneCheck(int name)
-{
- Node *check = createNode(opBuilder()->get<Meta::IsEmpty>(), env()->accumulator());
- createNode(opBuilder()->get<Meta::Branch>(), check);
-
- { //### it's probably better to handle this by de-optimizing
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- createNode(opBuilder()->get<Meta::ThrowReferenceError>(),
- createConstant(name));
- startUnwinding();
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_ThrowException()
-{
- createNode(opBuilder()->get<Meta::Throw>(), env()->accumulator());
- startUnwinding();
-}
-
-void GraphBuilder::generate_GetException()
-{
- bindAcc(createNode(opBuilder()->get<Meta::GetException>()));
-}
-
-void GraphBuilder::generate_SetException()
-{
- createNode(opBuilder()->get<Meta::SetException>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_CreateCallContext()
-{
- createNode(opBuilder()->get<Meta::JSCreateCallContext>());
-}
-
-void GraphBuilder::generate_PushCatchContext(int index, int name)
-{
- createNode(opBuilder()->get<Meta::JSCreateCatchContext>(),
- createConstant(index),
- createConstant(name));
-}
-
-void GraphBuilder::generate_PushWithContext()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateWithContext>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_PushBlockContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateBlockContext>(),
- createConstant(index));
-}
-
-void GraphBuilder::generate_CloneBlockContext()
-{
- createNode(opBuilder()->get<Meta::JSCloneBlockContext>());
-}
-
-void GraphBuilder::generate_PushScriptContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateScriptContext>(), createConstant(index));
-}
-
-void GraphBuilder::generate_PopScriptContext()
-{
- createNode(opBuilder()->get<Meta::JSPopScriptContext>());
-}
-
-void GraphBuilder::generate_PopContext()
-{
- createNode(opBuilder()->get<Meta::PopContext>());
-}
-
-void GraphBuilder::generate_GetIterator(int iterator)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetIterator>(),
- env()->accumulator(),
- createConstant(iterator)));
-}
-
-void GraphBuilder::generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode,
- int resultSlot)
-{
- // See generate_IteratorNext for why this method exists.
-
- // check that no-one messed around with the operation and made it throwing
- Q_ASSERT(iterationNode->operation()->controlOutputCount() == 1);
-
- // check that it's in the effect chain, because HasException relies on that
- Q_ASSERT(iterationNode->operation()->effectOutputCount() == 1);
-
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::SelectOutput>(),
- iterationNode,
- createConstant(1),
- graph()->undefinedNode()),
- resultSlot);
- // Note: the following will NOT set the accumulator, because it contains the return value of
- // the runtime call!
- Node *ehCheck = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), ehCheck);
-
- { // EH path:
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- if (auto ehOffset = env()->unwindHandlerOffset()) {
- // Ok, there is an exception handler, so go there:
- mergeIntoSuccessor(ehOffset);
- } else {
- // No Exception Handler, so keep the exception set in the engine, and leave the function
- // a.s.a.p.:
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
- }
-
- // Normal control flow:
- createIfFalse();
-}
-
-void GraphBuilder::generate_IteratorNext(int value, int done)
-{
- // The way we model exceptions in the graph is that a runtime function will either succeed and
- // return a value, or it fails and throws an exception. If it throws, the return value is not
- // used because the method did not complete normally, and therefore it might be tainted.
- //
- // This is a problem for (and only for) IteratorNext and IteratorNextForYieldStart.
- //
- // What would happen in the normal case, is that the return value (done) is not used/assigned
- // when IteratorNext throws, because the exception handling path is chosen. However, the
- // interpreter *does* assign it, and will only check for an exception *after* that assignment.
- //
- // So, in order to work around this odd-duck behavior, we mark the operation as NoThrow,
- // override the runtime method and flag it to not throw, and insert extra exception check nodes
- // after the SelectOutput that follows the IteratorNext(ForYieldStar).
- //
- // Also note that the IteratorNext and IteratorNextForYieldStar are the only operations that
- // have an inout parameter, and thus require a SelectOutput node to retrieve this.
-
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNext>(),
- env()->accumulator(),
- graph()->undefinedNode());
- bindAcc(n);
- env()->bindNodeToSlot(n, done);
- generate_IteratorNextAndFriends_TrailingStuff(n, value);
-}
-
-void GraphBuilder::generate_IteratorNextForYieldStar(int iterator, int object)
-{
- // Please, PLEASE read the comment in generate_IteratorNext.
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNextForYieldStar>(),
- env()->accumulator(),
- env()->slot(iterator),
- graph()->undefinedNode());
- // Note: the following is a tiny bit different from what generate_IteratorNext does.
- bindAcc(n);
- generate_IteratorNextAndFriends_TrailingStuff(n, object);
-}
-
-void GraphBuilder::generate_IteratorClose(int done)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIteratorClose>(),
- env()->accumulator(),
- env()->slot(done)));
-}
-
-void GraphBuilder::generate_DestructureRestElement()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDestructureRestElement>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeleteProperty(int base, int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteProperty>(),
- env()->slot(base),
- env()->slot(index)));
-}
-
-void GraphBuilder::generate_DeleteName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofValue()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofValue>(), env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeclareVar(int varName, int isDeletable)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeclareVar>(),
- createConstant(isDeletable),
- createConstant(varName)));
-}
-
-void GraphBuilder::generate_DefineArray(int argc, int argv)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSDefineArray, args, argc, argv);
-}
-
-void GraphBuilder::generate_DefineObjectLiteral(int internalClassId, int argc, int argv)
-{
- VarArgNodes args;
- args.append(createConstant(internalClassId));
- finalizeCall(Meta::JSDefineObjectLiteral, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateClass(int classIndex, int heritage, int computedNames)
-{
- int argc = 0;
- int argv = computedNames;
-
- const QV4::CompiledData::Class *cls = function()->v4Function()->compilationUnit->unitData()
- ->classAt(classIndex);
- const CompiledData::Method *methods = cls->methodTable();
- for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
- if (methods[i].name == std::numeric_limits<unsigned>::max())
- ++argc;
- }
-
- VarArgNodes args;
- args.append(createConstant(classIndex));
- args.append(env()->slot(heritage));
- finalizeCall(Meta::JSCreateClass, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateMappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateMappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateUnmappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateUnmappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateRestParameter(int argIndex)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateRestParameter>(),
- createConstant(argIndex)));
-}
-
-void GraphBuilder::generate_ConvertThisToObject()
-{
- Node* control = createNode(opBuilder()->get<Meta::JSThisToObject>(),
- env()->slot(CallData::This));
- env()->bindNodeToSlot(control, CallData::This);
-}
-
-void GraphBuilder::generate_LoadSuperConstructor()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperConstructor>(),
- env()->slot(CallData::Function)));
-}
-
-void GraphBuilder::generate_ToObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::ToObject>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_TailCall(int func, int thisObject, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- populate(args, argc, argv);
- Node *n = createAndLinkNode(opBuilder()->getJSTailCall(uint16_t(args.size())), args.data(),
- size_t(args.size()));
- queueFunctionExit(n);
-}
-
-void GraphBuilder::generate_Construct(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstruct, args, argc, argv);
-}
-
-void GraphBuilder::generate_ConstructWithSpread(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstructWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_Jump(int offset)
-{
- auto jumpTarget = absoluteOffset(offset);
- mergeIntoSuccessor(jumpTarget);
-}
-
-void GraphBuilder::generate_JumpTrue(int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(env()->accumulator()));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfTrue();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_JumpFalse(int traceSlot, int offset)
-{
- generate_JumpFalse(env()->accumulator(), traceSlot, offset);
-}
-
-void GraphBuilder::generate_JumpFalse(Node *condition, int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(condition));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNoException(int offset)
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNotUndefined(int offset)
-{
- Node *condition = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->accumulator(),
- graph()->undefinedNode());
- generate_JumpFalse(condition, NoTraceSlot, offset);
-}
-
-void GraphBuilder::generate_CmpEqNull()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->accumulator(),
- graph()->nullNode()));
-}
-
-void GraphBuilder::generate_CmpNeNull()
-{
- generate_CmpEqNull();
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEqInt(int lhs)
-{
- auto left = createConstant(lhs);
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- left,
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNeInt(int lhs)
-{
- generate_CmpEqInt(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEq(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNe(int lhs)
-{
- generate_CmpEq(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpGt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpGe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictEqual(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictNotEqual(int lhs)
-{
- generate_CmpStrictEqual(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpIn(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIn>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpInstanceOf(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSInstanceOf>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UNot()
-{
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- createToBoolean(env()->accumulator())));
-}
-
-void GraphBuilder::generate_UPlus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSToNumber>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UMinus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSNegate>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UCompl()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(-1)));
-}
-
-void GraphBuilder::generate_Increment(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-
-void GraphBuilder::generate_Decrement(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-void GraphBuilder::generate_Add(int lhs, int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_BitAnd(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitOr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitXor(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UShr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shl(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-
-void GraphBuilder::generate_BitAndConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitOrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitXorConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_UShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShlConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_Exp(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSExponentiate>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mul(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSMultiply>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Div(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDivide>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mod(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSModulo>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Sub(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
-{
- for (int reg = firstReg; reg < firstReg + count; ++reg)
- env()->bindNodeToSlot(graph()->emptyNode(), reg);
-}
-
-void GraphBuilder::generate_ThrowOnNullOrUndefined()
-{
- createNode(opBuilder()->get<Meta::JSThrowOnNullOrUndefined>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_GetTemplateObject(int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetTemplateObject>(),
- createConstant(index)));
-}
-
-GraphBuilder::Verdict GraphBuilder::startInstruction(Moth::Instr::Type /*instr*/)
-{
- // This handles a couple of cases on how flow control can end up at this instruction.
-
- const auto off = currentInstructionOffset();
- if (auto newEnv = m_envForOffset[off]) {
- // Ok, there was a jump from before to this point (which registered an environment), so we
- // have two options:
- if (env() != newEnv && env() != nullptr) {
- // There is a current environment different from the environment active when we took the
- // jump. This happens with e.g. an if-then-else:
- //
- // acc = condition
- // JumpFalse else-block
- // ... then block
- // Jump end-if
- // else-block:
- // ... else block
- // end-if:
- // .. some instruction <--- we're here
- //
- // in that case we merge the after-else environment into the after-then environment:
- newEnv->merge(env());
- } else {
- // There is not a current environment. This can happen with e.g. a loop:
- // loop-start:
- // acc = condition
- // JumpFalse loop-end
- // ... loop body
- // Jump loop-start
- // loop-end:
- // .... some instruction <--- we're here
- //
- // The last jump of the loop will clear the environment, so at this point we only have
- // the environment registered by the JumpFalse. This is the asy case: no merges, just
- // take the registered environment unchanged.
- }
-
- // Leave the merged environment as-is, and continue with a copy. We cannot change the
- // registered environment in case this point also happens to be a loop start.
- setEnv(newEnv->copy());
- }
-
- if (env() == nullptr) {
- // Ok, there is no environment, meaning nobody jumped to this instruction, and the previous
- // instruction doesn't let control flow end up here. So, this is dead code.
- // This can happen for JS like:
- //
- // if (condition) {
- // return something
- // } else {
- // return somethingElse
- // }
- // someCode <--- we're here
- return SkipInstruction;
- }
-
- const LabelInfo *info = isLoopStart(off);
- if (info && env()) {
- // Ok, this instruction is the start of a loop, meaning there will be a jump backwards to
- // this point. Make sure there is a Region node with Phi nodes here.
- handleLoopStart(*info);
- }
-
- return ProcessInstruction;
-}
-
-void GraphBuilder::endInstruction(Moth::Instr::Type /*instr*/) {}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graphbuilder_p.h b/src/qml/jit/qv4graphbuilder_p.h
deleted file mode 100644
index 450d8640b7..0000000000
--- a/src/qml/jit/qv4graphbuilder_p.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPHBUILDER_P_H
-#define QV4GRAPHBUILDER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4global_p.h>
-#include <private/qv4bytecodehandler_p.h>
-#include <private/qv4ir_p.h>
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// The graph builder walks the byte-code, and produces a graph. The graph is a digraph, where the
-// nodes have operations, and the edges are dependencies (or inputs).
-class GraphBuilder: protected Moth::ByteCodeHandler
-{
- Q_DISABLE_COPY_MOVE(GraphBuilder)
-
- enum { NoTraceSlot = -1 };
-
- struct LabelInfo { //### extend this to also capture the amount of slots that are live
- LabelInfo() = default;
- LabelInfo(unsigned label) : labelOffset(label) {}
- unsigned labelOffset = 0;
- };
-
-public:
- static void buildGraph(IR::Function *function);
-
- class InterpreterEnvironment;
-
- void setEnv(InterpreterEnvironment *newEnv)
- { m_currentEnv = newEnv; }
-
- InterpreterEnvironment *env() const
- { return m_currentEnv; }
-
-private:
- GraphBuilder(IR::Function *function);
- ~GraphBuilder() override = default;
-
- void startGraph();
- void endGraph();
-
- Node *bindAcc(Node *n);
- Node *createAndLinkNode(Operation *op, Node *operands[], size_t opCount, bool incomplete = false);
- Node *createNode(Operation *op, bool incomplete = false);
- Node *createNode(Operation *op, Node *n1);
- Node *createNode(Operation *op, Node *n1, Node *n2);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4);
- Node *createRegion(unsigned nControlInputs);
- Node *createIfTrue();
- Node *createIfFalse();
- Node *createConstant(int v);
- Node *createPhi(unsigned nInputs, Node *input, Node *control);
- Node *createEffectPhi(unsigned nInputs, Node *input, Node *control);
- Node *createHandleUnwind(int offset);
- Node *mergeControl(Node *c1, Node *c2);
- Node *mergeEffect(Node *e1, Node *e2, Node *control);
- Node *mergeValue(Node *v1, Node *v2, Node *control);
-
- Node *createToBoolean(Node *input);
-
- using VarArgNodes = QVarLengthArray<Node *, 32>;
- void populate(VarArgNodes &args, int argc, int argv);
-
- void queueFunctionExit(Node *exitNode);
-
- Function *function() const
- { return m_func; }
-
- Graph *graph()
- { return m_graph; }
-
- Node *mergeIntoSuccessor(int offset);
-
- OperationBuilder *opBuilder() const
- { return m_graph->opBuilder(); }
-
- int absoluteOffset(int offset) const
- { return offset + nextInstructionOffset(); }
-
- const LabelInfo *labelInfoAt(unsigned offset) const;
- const LabelInfo *isLoopStart(unsigned offset) const;
- void handleLoopStart(const LabelInfo &labelInfo);
- void startUnwinding();
-
-protected: // ByteCodeHandler
- void generate_Ret() override;
- void generate_Debug() override;
- void generate_LoadConst(int index) override;
- void generate_LoadZero() override;
- void generate_LoadTrue() override;
- void generate_LoadFalse() override;
- void generate_LoadNull() override;
- void generate_LoadUndefined() override;
- void generate_LoadInt(int value) override;
- void generate_MoveConst(int constIndex, int destTemp) override;
- void generate_LoadReg(int reg) override;
- void generate_StoreReg(int reg) override;
- void generate_MoveReg(int srcReg, int destReg) override;
- void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
- void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
- void generate_StoreScopedLocal(int scope, int index) override;
- void generate_LoadRuntimeString(int stringId) override;
- void generate_MoveRegExp(int regExpId, int destReg) override;
- void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_StoreNameSloppy(int name) override;
- void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
- void generate_StoreProperty(int name, int base) override;
- void generate_SetLookup(int index, int base) override;
- void generate_LoadSuperProperty(int property) override;
- void generate_StoreSuperProperty(int property) override;
- void generate_LoadQmlContextPropertyLookup(int property, int traceSlot) override;
- void generate_Yield() override;
- void generate_YieldStar() override;
- void generate_Resume(int offset) override;
- void finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv);
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_SetUnwindHandler(int offset) override;
- void generate_UnwindDispatch() override;
- void generate_UnwindToLabel(int level, int offset) override;
- void generate_DeadTemporalZoneCheck(int name) override;
- void generate_ThrowException() override;
- void generate_GetException() override;
- void generate_SetException() override;
- void generate_CreateCallContext() override;
- void generate_PushCatchContext(int index, int name) override;
- void generate_PushWithContext() override;
- void generate_PushBlockContext(int index) override;
- void generate_CloneBlockContext() override;
- void generate_PushScriptContext(int index) override;
- void generate_PopScriptContext() override;
- void generate_PopContext() override;
- void generate_GetIterator(int iterator) override;
- void generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode, int resultSlot);
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
- void generate_DestructureRestElement() override;
- void generate_DeleteProperty(int base, int index) override;
- void generate_DeleteName(int name) override;
- void generate_TypeofName(int name) override;
- void generate_TypeofValue() override;
- void generate_DeclareVar(int varName, int isDeletable) override;
- void generate_DefineArray(int argc, int argv) override;
- void generate_DefineObjectLiteral(int internalClassId, int argc, int argv) override;
- void generate_CreateClass(int classIndex, int heritage, int computedNames) override;
- void generate_CreateMappedArgumentsObject() override;
- void generate_CreateUnmappedArgumentsObject() override;
- void generate_CreateRestParameter(int argIndex) override;
- void generate_ConvertThisToObject() override;
- void generate_LoadSuperConstructor() override;
- void generate_ToObject() override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_TailCall(int func, int thisObject, int argc, int argv) override;
- void generate_Construct(int func, int argc, int argv) override;
- void generate_ConstructWithSpread(int func, int argc, int argv) override;
- void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
- void generate_JumpFalse(Node *condition, int traceSlot, int offset);
- void generate_JumpNoException(int offset) override;
- void generate_JumpNotUndefined(int offset) override;
- void generate_CmpEqNull() override;
- void generate_CmpNeNull() override;
- void generate_CmpEqInt(int lhs) override;
- void generate_CmpNeInt(int lhs) override;
- void generate_CmpEq(int lhs) override;
- void generate_CmpNe(int lhs) override;
- void generate_CmpGt(int lhs) override;
- void generate_CmpGe(int lhs) override;
- void generate_CmpLt(int lhs) override;
- void generate_CmpLe(int lhs) override;
- void generate_CmpStrictEqual(int lhs) override;
- void generate_CmpStrictNotEqual(int lhs) override;
- void generate_CmpIn(int lhs) override;
- void generate_CmpInstanceOf(int lhs) override;
- void generate_UNot() override;
- void generate_UPlus(int traceSlot) override;
- void generate_UMinus(int traceSlot) override;
- void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
- void generate_BitAnd(int lhs) override;
- void generate_BitOr(int lhs) override;
- void generate_BitXor(int lhs) override;
- void generate_UShr(int lhs) override;
- void generate_Shr(int lhs) override;
- void generate_Shl(int lhs) override;
- void generate_BitAndConst(int rhs) override;
- void generate_BitOrConst(int rhs) override;
- void generate_BitXorConst(int rhs) override;
- void generate_UShrConst(int rhs) override;
- void generate_ShrConst(int rhs) override;
- void generate_ShlConst(int rhs) override;
- void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
- void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
- void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
- void generate_ThrowOnNullOrUndefined() override;
- void generate_GetTemplateObject(int index) override;
-
- Verdict startInstruction(Moth::Instr::Type instr) override;
- void endInstruction(Moth::Instr::Type instr) override;
-
-private:
- IR::Function *m_func;
- Graph *m_graph;
- InterpreterEnvironment *m_currentEnv;
- std::vector<Node *> m_exitControls;
- QHash<int, InterpreterEnvironment *> m_envForOffset;
- std::vector<LabelInfo> m_labelInfos;
- int m_currentUnwindHandlerOffset = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPHBUILDER_P_H
diff --git a/src/qml/jit/qv4ir.cpp b/src/qml/jit/qv4ir.cpp
deleted file mode 100644
index cb3eeeec60..0000000000
--- a/src/qml/jit/qv4ir.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qqmlglobal_p.h>
-#include "qv4ir_p.h"
-#include "qv4node_p.h"
-#include "qv4function_p.h"
-#include <qv4graph_p.h>
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-#include "qv4util_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qfile.h>
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcJsonIR, "qt.v4.ir.json");
-Q_LOGGING_CATEGORY(lcDotIR, "qt.v4.ir.dot");
-Q_LOGGING_CATEGORY(lcVerify, "qt.v4.ir.verify");
-
-Function::Function(QV4::Function *qv4Function)
- : qv4Function(qv4Function)
- , m_graph(Graph::create(this))
- , m_dumper(nullptr)
- , m_nodeInfo(128, nullptr)
-{
-}
-
-Function::~Function()
-{
- delete m_dumper;
-}
-
-QString Function::name() const
-{
- QString name;
- if (auto n = v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- name = QString::asprintf("%p", v4Function());
- auto loc = v4Function()->sourceLocation();
- return name + QStringLiteral(" (%1:%2:%3)").arg(loc.sourceFile, QString::number(loc.line),
- QString::number(loc.column));
-}
-
-void Function::dump(const QString &description) const
-{
- Dumper::dump(this, description);
-}
-
-void Function::dump() const
-{
- dump(QStringLiteral("Debug:"));
-}
-
-Dumper *Function::dumper() const
-{
- if (!m_dumper)
- m_dumper = new Dumper(this);
- return m_dumper;
-}
-
-Function::StringId Function::addString(const QString &s)
-{
- m_stringPool.push_back(s);
- return m_stringPool.size() - 1;
-}
-
-NodeInfo *Function::nodeInfo(Node *n, bool createIfNecessary) const
-{
- if (n->id() >= m_nodeInfo.size())
- m_nodeInfo.resize(n->id() * 2, nullptr);
-
- NodeInfo *&info = m_nodeInfo[n->id()];
- if (info == nullptr && createIfNecessary) {
- info = m_pool.New<NodeInfo>();
- info->setType(n->operation()->type());
- }
- return info;
-}
-
-void Function::copyBytecodeOffsets(Node *from, Node *to)
-{
- auto toInfo = nodeInfo(to);
- if (auto fromInfo = nodeInfo(from)) {
- toInfo->setBytecodeOffsets(fromInfo->currentInstructionOffset(),
- fromInfo->nextInstructionOffset());
- }
-}
-
-Dumper::Dumper(const Function *f)
-{
- if (!f)
- return;
-}
-
-void Dumper::dump(const Function *f, const QString &description)
-{
- if (false && lcJsonIR().isDebugEnabled()) {
- Dumper *dumper = f->dumper();
-
- qCDebug(lcJsonIR).noquote().nospace() << description + QLatin1String(":\n");
- for (const auto &line : dumper->dump(f).split('\n'))
- qCDebug(lcJsonIR).noquote().nospace() << line;
- }
-
- if (lcDotIR().isDebugEnabled())
- dot(f, description);
-}
-
-QByteArray Dumper::dump(const Function *f)
-{
- QJsonObject fo;
-
- {
- QString name;
- if (auto n = f->v4Function()->name())
- name = n->toQString();
- fo[QLatin1String("_searchKey")] = QStringLiteral("function %1").arg(name);
- if (name.isEmpty())
- name = QString::asprintf("%p", f->v4Function());
- fo[QLatin1String("name")] = name;
- }
-
- auto loc = f->v4Function()->sourceLocation();
- fo[QLatin1String("source")] = loc.sourceFile;
- fo[QLatin1String("line")] = loc.line;
- fo[QLatin1String("column")] = loc.column;
-
- {
- QJsonArray gn;
- QJsonArray ge;
- NodeCollector nodes(f->graph(), /*collectUses =*/ true);
- nodes.sortById();
- for (Node *n : nodes.reachable()) {
- gn.append(dump(n, f));
- int inputIndex = 0;
- for (Node *input : n->inputs()) {
- QJsonObject edge;
- edge[QLatin1String("from")] = int(input->id());
- edge[QLatin1String("to")] = int(n->id());
- edge[QLatin1String("index")] = inputIndex;
- if (inputIndex < n->operation()->valueInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("value");
- } else if (inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("effect");
- } else {
- edge[QLatin1String("type")] = QLatin1String("control");
- }
- Q_ASSERT(inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()
- + n->operation()->controlInputCount());
- ge.append(edge);
- ++inputIndex;
- }
- }
- QJsonObject g;
- g[QLatin1String("nodes")] = gn;
- g[QLatin1String("edges")] = ge;
- fo[QLatin1String("graph")] = g;
- }
-
- m_doc.setObject(fo);
- return m_doc.toJson(QJsonDocument::Indented);
-}
-
-QJsonValue toJSonValue(QV4::Value v)
-{
- switch (v.type()) {
- case QV4::Value::Undefined_Type: return QJsonValue(QJsonValue::Undefined);
- case QV4::Value::Null_Type: return QJsonValue(QJsonValue::Null);
- case QV4::Value::Boolean_Type: return QJsonValue(v.booleanValue());
- case QV4::Value::Integer_Type: return QJsonValue(v.int_32());
- case QV4::Value::Managed_Type:
- if (String *s = v.stringValue())
- return QJsonValue(s->toQString());
- else
- return QJsonValue(QLatin1String("<managed>"));
- default: return QJsonValue(v.doubleValue());
- }
-}
-
-QJsonValue Dumper::dump(const Node * const node, const Function *f)
-{
- QJsonObject n;
- n[QLatin1String("id")] = int(node->id());
- n[QLatin1String("kind")] = node->operation()->debugString();
- switch (node->operation()->kind()) {
- case Meta::Parameter: {
- auto info = ParameterPayload::get(*node->operation());
- n[QLatin1String("name")] = f->string(info->stringId());
- n[QLatin1String("index")] = int(info->parameterIndex());
- break;
- }
- case Meta::Constant: {
- auto info = ConstantPayload::get(*node->operation());
- n[QLatin1String("value")] = toJSonValue(info->value());
- break;
- }
- default:
- break;
- }
- return n;
-}
-
-void Dumper::dot(const Function *f, const QString &description)
-{
- static const bool skipFramestate = qEnvironmentVariableIsSet("QV4_JIT_DOT_SKIP_FRAMESTATE");
-
- auto node = [](Node *n) {
- return QStringLiteral("n%1[label=\"%1: %2%3\"];\n").arg(QString::number(n->id()),
- n->operation()->debugString(),
- n->isDead() ? QStringLiteral(" (dead)")
- : QString());
- };
-
- Graph *g = f->graph();
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"n%1\" label=\"%2\";"
- "node[shape=rect];"
- "edge[dir=back fontsize=10];\n")
- .arg(g->startNode()->id())
- .arg(description);
- out += node(g->startNode());
- const bool dumpUses = false; // set to true to see all nodes
- NodeCollector nodes(g, dumpUses, skipFramestate);
- for (Node *n : nodes.reachable()) {
- if (n == g->startNode())
- continue;
-
- out += node(n);
-
- unsigned inputIndex = 0;
- for (Node *input : n->inputs()) {
- if (input == nullptr)
- continue;
- out += QStringLiteral("n%2->n%1[style=").arg(QString::number(n->id()),
- QString::number(input->id()));
- if (inputIndex < n->operation()->valueInputCount() ||
- inputIndex == n->operation()->indexOfFrameStateInput()) {
- out += QStringLiteral("solid headlabel=\"%1\"").arg(inputIndex);
- } else if (inputIndex < unsigned(n->operation()->valueInputCount()
- + n->operation()->effectInputCount())) {
- out += QStringLiteral("dotted headlabel=\"%1\"").arg(inputIndex);
- } else {
- out += QStringLiteral("dashed headlabel=\"%1\"").arg(inputIndex);
- }
- out += QStringLiteral("];\n");
- ++inputIndex;
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotIR).nospace().noquote() << out;
-
- QFile of(description + QStringLiteral(".dot"));
- of.open(QIODevice::WriteOnly);
- of.write(out.toUtf8());
- of.close();
-}
-
-void Function::verify() const
-{
-#ifndef QT_NO_DEBUG
- unsigned problemsFound = 0;
-
- auto verifyNodeAgainstOperation = [&problemsFound](const Node *n) {
- const Operation *op = n->operation();
- if (op->totalInputCount() != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Node" << n->id() << "has" << n->inputCount()
- << "inputs, but it's operation" << op->debugString()
- << "requires" << op->totalInputCount() << "inputs";
- }
-
- if (n->opcode() == Meta::Phi || n->opcode() == Meta::EffectPhi) {
- if (n->controlInput()->opcode() != Meta::Region) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id() << "is not a region";
- }
- if (n->controlInput()->inputCount() + 1 != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id()
- << "has" << n->controlInput()->inputCount()
- << "inputs while phi node has" << n->inputCount()
- << "inputs";
- }
- }
-
- //### todo: verify outputs: value outputs are allowed to be unused, but the effect and
- // control outputs have to be linked up, except:
- //### todo: verify if no use is a nullptr, except for operations that can throw, where the
- // last one is allowed to be a nullptr when an unwind handler is missing.
- };
-
- NodeWorkList todo(graph());
- todo.enqueue(graph()->endNode());
- while (Node *n = todo.dequeueNextNodeForVisiting()) {
- todo.enqueueAllInputs(n);
- todo.enqueueAllUses(n);
-
- verifyNodeAgainstOperation(n);
- }
- //### TODO:
- if (problemsFound != 0) {
- dump(QStringLiteral("Problematic graph"));
- qFatal("Found %u problems during graph verification!", problemsFound);
- }
-#endif // QT_NO_xDEBUG
-}
-
-QString Type::debugString() const
-{
- if (isNone())
- return QStringLiteral("none");
- if (isInvalid())
- return QStringLiteral("invalid");
-
- QStringList s;
- if (m_t & Bool)
- s += QStringLiteral("boolean");
- if (m_t & Int32)
- s += QStringLiteral("int32");
- if (m_t & Double)
- s += QStringLiteral("double");
- if (m_t & Undefined)
- s += QStringLiteral("undefined");
- if (m_t & Null)
- s += QStringLiteral("null");
- if (m_t & Empty)
- s += QStringLiteral("empty");
- if (m_t & RawPointer)
- s += QStringLiteral("raw pointer");
-
- return s.join(QLatin1String(" "));
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4ir_p.h b/src/qml/jit/qv4ir_p.h
deleted file mode 100644
index e21a80528d..0000000000
--- a/src/qml/jit/qv4ir_p.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4IR_P_H
-#define QV4IR_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4function_p.h>
-#include <QtCore/qjsondocument.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Dumper;
-class Graph;
-
-class Node;
-class NodeInfo;
-
-class Function
-{
- Q_DISABLE_COPY_MOVE(Function)
-public:
- Function(QV4::Function *qv4Function);
- ~Function();
-
- void verify() const;
-
- QV4::Function *v4Function() const
- { return qv4Function; }
-
- QString name() const;
-
- QQmlJS::MemoryPool *pool()
- { return &m_pool; }
-
- Graph *graph() const
- { return m_graph; }
-
- void dump(const QString &description) const;
- void dump() const; // for calling in the debugger
- Dumper *dumper() const;
-
- using StringId = size_t;
- StringId addString(const QString &s);
- QString string(StringId id) const
- { return m_stringPool[id]; }
-
- NodeInfo *nodeInfo(Node *n, bool createIfNecessary = true) const;
- void copyBytecodeOffsets(Node *from, Node *to);
-
- void addUnwindLabelOffset(int absoluteOffset)
- { m_unwindLabelOffsets.push_back(absoluteOffset); }
-
- const std::vector<int> &unwindLabelOffsets() const
- { return m_unwindLabelOffsets; }
-
-private:
- QV4::Function *qv4Function;
- mutable QQmlJS::MemoryPool m_pool;
- Graph *m_graph;
- mutable Dumper *m_dumper;
- std::vector<QString> m_stringPool;
- mutable std::vector<NodeInfo *> m_nodeInfo; //### move the into the _pool
- std::vector<int> m_unwindLabelOffsets;
-};
-
-class Dumper
-{
- Q_DISABLE_COPY_MOVE(Dumper)
-
-public:
- Dumper(const Function *f);
- ~Dumper() = default;
-
- static void dump(const Function *f, const QString &description);
- static void dot(const Function *f, const QString &description);
-
-private:
- QByteArray dump(const Function *f);
- QJsonValue dump(const Node *node, const Function *f);
-
-private:
- QJsonDocument m_doc;
-};
-
-class Type
-{
- // None is for nodes with no type (e.g. a Return)
- // The others form a lattice:
- // Any -> Object -> Invalid
- // ^^^ -> Number -> Integral -> Int32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> UInt32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> Bool -> ^^^^^^^
- // ^^^ -> Number -> Double -> ^^^^^^^
- // ^^^ -> Undefined -> ^^^^^^^
- // ^^^ -> Null -> ^^^^^^^
- // ^^^ -> Empty -> ^^^^^^^
- enum InternalType: int16_t {
- None = 0,
-
- Object = 1 << 0,
- Bool = 1 << 1,
- Int32 = 1 << 2,
- UInt32 = 1 << 3,
- Double = 1 << 4,
- Undefined = 1 << 5,
- Null = 1 << 6,
- Empty = 1 << 7,
- RawPointer = 1 << 8,
- Invalid = -1,
-
- Integral = Int32 | UInt32 | Bool,
- Number = Integral | Double,
- Any = Object | Number | Undefined | Empty | Null,
- };
-
- Type(InternalType t) : m_t(t) {}
-
-public:
- Type() = default;
-
- bool operator==(const Type &other) const
- { return m_t == other.m_t; }
-
- static Type noneType() { return Type(None); }
- static Type anyType() { return Type(Any); }
- static Type undefinedType() { return Type(Undefined); }
- static Type emptyType() { return Type(Empty); }
- static Type booleanType() { return Type(Bool); }
- static Type int32Type() { return Type(Int32); }
- static Type doubleType() { return Type(Double); }
- static Type numberType() { return Type(Number); }
- static Type nullType() { return Type(Null); }
- static Type objectType() { return Type(Object); }
- static Type rawPointerType() { return Type(RawPointer); }
-
- bool isAny() const { return m_t == Any; }
- bool isBoolean() const { return m_t == Bool; }
- bool isInt32() const { return m_t == Int32; }
- bool isInvalid() const { return m_t == Invalid; }
- bool isNone() const { return m_t == None; }
- bool isDouble() const { return m_t == Double; }
- bool isUndefined() const { return m_t == Undefined; }
- bool isNull() const { return m_t == Null; }
- bool isEmpty() const { return m_t == Empty; }
- bool isObject() const { return m_t == Object; }
- bool isRawPointer() const { return m_t == RawPointer; }
- bool isIntegral() const { return matches(Integral); }
- bool isNumber() const { return matches(Number); }
-
- Type operator|(Type other) const
- { return Type(InternalType(int16_t(m_t) | int16_t(other.m_t))); }
-
- Type &operator|=(Type other)
- {
- m_t = (InternalType(int16_t(m_t) | int16_t(other.m_t)));
- return *this;
- }
-
- QString debugString() const;
-
-private:
- bool matches(InternalType it) const
- {
- return (m_t & ~it) == 0 && (m_t & it) != 0;
- }
-
-private:
- InternalType m_t = None;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4IR_P_H
diff --git a/src/qml/jit/qv4loopinfo.cpp b/src/qml/jit/qv4loopinfo.cpp
deleted file mode 100644
index 0366c49e30..0000000000
--- a/src/qml/jit/qv4loopinfo.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4loopinfo_p.h"
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLoopinfo, "qt.v4.ir.loopinfo")
-
-void LoopInfo::detectLoops()
-{
- blockInfos.resize(dt.function()->blockCount());
-
- std::vector<MIBlock *> backedges;
- backedges.reserve(4);
-
- const auto order = dt.calculateDFNodeIterOrder();
- for (MIBlock *bb : order) {
- if (bb->isDeoptBlock())
- continue;
-
- backedges.clear();
-
- for (MIBlock *pred : bb->inEdges()) {
- if (bb == pred || dt.dominates(bb->index(), pred->index()))
- backedges.push_back(pred);
- }
-
- if (!backedges.empty())
- subLoop(bb, backedges);
- }
-
- collectLoopExits();
-
- dump();
-}
-
-void LoopInfo::collectLoopExits()
-{
- for (MIBlock::Index i = 0, ei = MIBlock::Index(blockInfos.size()); i != ei; ++i) {
- BlockInfo &bi = blockInfos[i];
- MIBlock *currentBlock = dt.function()->block(i);
- if (bi.isLoopHeader) {
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != currentBlock && !inLoopOrSubLoop(outEdge, currentBlock))
- bi.loopExits.push_back(outEdge);
- }
- }
- if (MIBlock *containingLoop = bi.loopHeader) {
- BlockInfo &loopInfo = blockInfos[containingLoop->index()];
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != containingLoop && !inLoopOrSubLoop(outEdge, containingLoop))
- loopInfo.loopExits.push_back(outEdge);
- }
- }
- }
-}
-
-bool LoopInfo::inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const
-{
- const BlockInfo &bi = blockInfos[block->index()];
- MIBlock *loopHeaderForBlock = bi.loopHeader;
- if (loopHeaderForBlock == nullptr)
- return false; // block is not in any loop
-
- while (loopHeader) {
- if (loopHeader == loopHeaderForBlock)
- return true;
- // look into the parent loop of loopHeader to see if block is contained there
- loopHeader = blockInfos[loopHeader->index()].loopHeader;
- }
-
- return false;
-}
-
-void LoopInfo::subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges)
-{
- blockInfos[loopHead->index()].isLoopHeader = true;
-
- std::vector<MIBlock *> worklist;
- worklist.reserve(backedges.size() + 8);
- worklist.insert(worklist.end(), backedges.begin(), backedges.end());
- while (!worklist.empty()) {
- MIBlock *predIt = worklist.back();
- worklist.pop_back();
-
- MIBlock *subloop = blockInfos[predIt->index()].loopHeader;
- if (subloop) {
- // This is a discovered block. Find its outermost discovered loop.
- while (MIBlock *parentLoop = blockInfos[subloop->index()].loopHeader)
- subloop = parentLoop;
-
- // If it is already discovered to be a subloop of this loop, continue.
- if (subloop == loopHead)
- continue;
-
- // Yay, it's a subloop of this loop.
- blockInfos[subloop->index()].loopHeader = loopHead;
- predIt = subloop;
-
- // Add all predecessors of the subloop header to the worklist, as long as
- // those predecessors are not in the current subloop. It might be the case
- // that they are in other loops, which we will then add as a subloop to the
- // current loop.
- for (MIBlock *predIn : predIt->inEdges())
- if (blockInfos[predIn->index()].loopHeader != subloop)
- worklist.push_back(predIn);
- } else {
- if (predIt == loopHead)
- continue;
-
- // This is an undiscovered block. Map it to the current loop.
- blockInfos[predIt->index()].loopHeader = loopHead;
-
- // Add all incoming edges to the worklist.
- for (MIBlock *bb : predIt->inEdges())
- worklist.push_back(bb);
- }
- }
-}
-
-void LoopInfo::dump() const
-{
- if (!lcLoopinfo().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Loop information:\n");
- for (size_t i = 0, ei = blockInfos.size(); i != ei; ++i) {
- const BlockInfo &bi = blockInfos[i];
- s += QStringLiteral(" %1 : is loop header: %2, contained in loop header's loop: ")
- .arg(i).arg(bi.isLoopHeader ? QLatin1String("yes") : QLatin1String("no"));
- if (bi.loopHeader)
- s += QString::number(bi.loopHeader->index());
- else
- s += QLatin1String("<none>");
- if (bi.isLoopHeader) {
- s += QStringLiteral(", loop exits: ");
- if (bi.loopExits.empty()) {
- s += QLatin1String("<none>");
- } else {
- bool first = true;
- for (MIBlock *exit : bi.loopExits) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QString::number(exit->index());
- }
- }
- }
- s += QLatin1Char('\n');
- }
- qCDebug(lcLoopinfo).noquote().nospace() << s;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4loopinfo_p.h b/src/qml/jit/qv4loopinfo_p.h
deleted file mode 100644
index 6a865e6dc6..0000000000
--- a/src/qml/jit/qv4loopinfo_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOOPINFO_P_H
-#define QV4LOOPINFO_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-
-#include <QHash>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-
-// Detect all (sub-)loops in a function.
-//
-// Doing loop detection on the CFG is better than relying on the statement information in
-// order to mark loops. Although JavaScript only has natural loops, it can still be the case
-// that something is not a loop even though a loop-like-statement is in the source. For
-// example:
-// while (true) {
-// if (i > 0)
-// break;
-// else
-// break;
-// }
-//
-// Algorithm:
-// - do a DFS on the dominator tree, where for each node:
-// - collect all back-edges
-// - if there are back-edges, the node is a loop-header for a new loop, so:
-// - walk the CFG is reverse-direction, and for every node:
-// - if the node already belongs to a loop, we've found a nested loop:
-// - get the loop-header for the (outermost) nested loop
-// - add that loop-header to the current loop
-// - continue by walking all incoming edges that do not yet belong to the current loop
-// - if the node does not belong to a loop yet, add it to the current loop, and
-// go on with all incoming edges
-//
-// Loop-header detection by checking for back-edges is very straight forward: a back-edge is
-// an incoming edge where the other node is dominated by the current node. Meaning: all
-// execution paths that reach that other node have to go through the current node, that other
-// node ends with a (conditional) jump back to the loop header.
-//
-// The exact order of the DFS on the dominator tree is not important. The only property has to
-// be that a node is only visited when all the nodes it dominates have been visited before.
-// The reason for the DFS is that for nested loops, the inner loop's loop-header is dominated
-// by the outer loop's header. So, by visiting depth-first, sub-loops are identified before
-// their containing loops, which makes nested-loop identification free. An added benefit is
-// that the nodes for those sub-loops are only processed once.
-//
-// Note: independent loops that share the same header are merged together. For example, in
-// the code snippet below, there are 2 back-edges into the loop-header, but only one single
-// loop will be detected.
-// while (a) {
-// if (b)
-// continue;
-// else
-// continue;
-// }
-class LoopInfo
-{
- Q_DISABLE_COPY_MOVE(LoopInfo)
-
- struct BlockInfo
- {
- MIBlock *loopHeader = nullptr;
- bool isLoopHeader = false;
- std::vector<MIBlock *> loopExits;
- };
-
-public:
- LoopInfo(const DominatorTree &dt)
- : dt(dt)
- {}
-
- ~LoopInfo() = default;
-
- void detectLoops();
-
- MIBlock *loopHeaderFor(MIBlock *bodyBlock) const
- { return blockInfos[bodyBlock->index()].loopHeader; }
-
- bool isLoopHeader(MIBlock *block) const
- { return blockInfos[block->index()].isLoopHeader; }
-
- const std::vector<MIBlock *> loopExitsForLoop(MIBlock *loopHeader) const
- { return blockInfos[loopHeader->index()].loopExits; }
-
-private:
- void subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges);
- void collectLoopExits();
- bool inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const;
-
- void dump() const;
-
-private:
- const DominatorTree &dt;
- std::vector<BlockInfo> blockInfos;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOOPINFO_P_H
diff --git a/src/qml/jit/qv4lowering.cpp b/src/qml/jit/qv4lowering.cpp
deleted file mode 100644
index 3b3711e7fa..0000000000
--- a/src/qml/jit/qv4lowering.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QLoggingCategory>
-
-#include "qv4lowering_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLower, "qt.v4.ir.lowering")
-
-GenericLowering::GenericLowering(Function &f)
- : m_function(f)
-{}
-
-void GenericLowering::lower()
-{
- NodeWorkList worklist(graph());
- // The order doesn't really matter for generic lowering, as long as it's done in 1 pass, and
- // have any clean-up done afterwards.
- worklist.enqueueAllInputs(graph()->endNode());
-
- while (Node *n = worklist.dequeueNextNodeForVisiting()) {
- worklist.enqueueAllInputs(n);
-
- if (!CallPayload::isRuntimeCall(n->opcode()))
- continue;
-
- if (CallPayload::isVarArgsCall(n->opcode()))
- replaceWithVarArgsCall(n);
- else
- replaceWithCall(n);
- }
-}
-
-void GenericLowering::replaceWithCall(Node *n)
-{
- auto newOp = opBuilder()->getCall(n->opcode());
-
- QVarLengthArray<Node *, 32> args;
- if (CallPayload::takesEngineAsArg(n->opcode(), 0))
- args.append(graph()->engineNode());
- if (CallPayload::takesFunctionAsArg(n->opcode(), args.size()))
- args.append(graph()->functionNode());
- if (CallPayload::takesFrameAsArg(n->opcode(), args.size()))
- args.append(graph()->cppFrameNode());
- const int extraLeadingArguments = args.size();
-
- for (unsigned arg = 0, earg = n->inputCount(); arg != earg; ++arg) {
- Node *input = n->input(arg);
- if (input->opcode() == Meta::FrameState)
- continue;
-
- if (arg >= n->operation()->valueInputCount()) {
- // effect or control input
- args.append(input);
- continue;
- }
-
- if (CallPayload::needsStorageOnJSStack(n->opcode(), args.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
-
- args.append(input);
- }
-
- Node *newCall = graph()->createNode(newOp, args.data(), args.size());
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- function().nodeInfo(newCall)->setType(CallPayload::returnType(n->opcode()));
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-
- for (Node *use : newCall->uses()) {
- // fix-up indices for SelectOutput:
- if (use->opcode() == Meta::SelectOutput) {
- const int oldIndex = ConstantPayload::get(*use->input(1)->operation())->value().int_32();
- const int newIndex = oldIndex + extraLeadingArguments;
- use->replaceInput(1, graph()->createConstantIntNode(newIndex));
- use->replaceInput(2, newCall->input(newIndex));
- break;
- }
- }
-}
-
-void GenericLowering::replaceWithVarArgsCall(Node *n)
-{
- const bool isTailCall = n->opcode() == Meta::JSTailCall;
- Operation *newOp = isTailCall ? opBuilder()->getTailCall()
- : opBuilder()->getCall(n->opcode());
-
- //### optimize this for 0 and 1 argument: we don't need to create a VarArgs array for these cases
-
- const unsigned varArgsStart = CallPayload::varArgsStart(n->opcode()) - 1; // subtract 1 because the runtime calls all take the engine argument as arg0, which isn't in the graph before lowering.
- Node *vaAlloc = graph()->createNode(
- opBuilder()->get<Meta::VAAlloc>(),
- graph()->createConstantIntNode(n->operation()->valueInputCount() - varArgsStart),
- n->effectInput());
- QVarLengthArray<Node *, 32> vaSealIn;
- vaSealIn.append(vaAlloc);
- for (unsigned i = varArgsStart, ei = n->operation()->valueInputCount(); i != ei; ++i) {
- vaSealIn.append(graph()->createNode(opBuilder()->get<Meta::VAStore>(), vaAlloc,
- graph()->createConstantIntNode(vaSealIn.size() - 1),
- n->input(i)));
- }
- vaSealIn.append(vaAlloc);
- Node *vaSeal = graph()->createNode(opBuilder()->getVASeal(vaSealIn.size() - 2),
- vaSealIn.data(),
- vaSealIn.size());
- QVarLengthArray<Node *, 8> callArgs;
- if (isTailCall)
- callArgs.append(graph()->cppFrameNode());
- callArgs.append(graph()->engineNode());
- for (unsigned i = 0; i != varArgsStart; ++i) {
- Node *input = n->input(i);
- if (CallPayload::needsStorageOnJSStack(n->opcode(), callArgs.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
- callArgs.append(input);
- }
- callArgs.append(vaSeal); // args
- if (n->opcode() != Meta::JSCreateClass) // JSCreateClass is the odd duck
- callArgs.append(graph()->createConstantIntNode(vaSealIn.size() - 2)); // argc
- callArgs.append(vaSeal); // effect
- callArgs.append(n->controlInput(0)); // control flow
- Node *newCall = graph()->createNode(newOp, callArgs.data(), unsigned(callArgs.size()));
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-}
-
-bool GenericLowering::allUsesAsUnboxedBool(Node *n)
-{
- for (Node *use : n->uses()) {
- if (use->operation()->kind() != Meta::Branch)
- return false;
- }
-
- return true;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4lowering_p.h b/src/qml/jit/qv4lowering_p.h
deleted file mode 100644
index 0b482bc9f0..0000000000
--- a/src/qml/jit/qv4lowering_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOWERING_P_H
-#define QV4LOWERING_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4util_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4graph_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Lowering replaces JS level operations with lower level ones. E.g. a JSAdd is lowered to an AddI32
-// if both inputs and the output are 32bit integers, or to a runtime call in all other cases. This
-// transforms the graph into something that is closer to actual executable code.
-
-
-// Last lowering phase: replace all JSOperations that are left with runtime calls. There is nothing
-// smart here, all that should have been done before this phase.
-class GenericLowering final
-{
- Q_DISABLE_COPY(GenericLowering)
-
-public:
- GenericLowering(Function &f);
-
- void lower();
-
-private:
- void replaceWithCall(Node *n);
- void replaceWithVarArgsCall(Node *n);
- static bool allUsesAsUnboxedBool(Node *n);
-
- Function &function()
- { return m_function; }
-
- Graph *graph()
- { return function().graph(); }
-
- OperationBuilder *opBuilder()
- { return graph()->opBuilder(); }
-
-private:
- Function &m_function;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOWERING_P_H
diff --git a/src/qml/jit/qv4mi.cpp b/src/qml/jit/qv4mi.cpp
deleted file mode 100644
index f0b172243d..0000000000
--- a/src/qml/jit/qv4mi.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <private/qqmlglobal_p.h>
-
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcMI, "qt.v4.ir.mi")
-
-QString MIOperand::debugString() const
-{
- switch (kind()) {
- case Invalid: return QStringLiteral("<<INVALID>>");
- case Constant: return ConstantPayload::debugString(constantValue());
- case VirtualRegister: return QStringLiteral("vreg%1").arg(virtualRegister());
- case EngineRegister: return QStringLiteral("engine");
- case CppFrameRegister: return QStringLiteral("cppFrame");
- case Function: return QStringLiteral("function");
- case JSStackSlot: return QStringLiteral("jsstack[%1]").arg(stackSlot());
- case BoolStackSlot: return QStringLiteral("bstack[%1]").arg(stackSlot());
- case JumpTarget: return targetBlock() ? QStringLiteral("L%1").arg(targetBlock()->index())
- : QStringLiteral("<<INVALID BLOCK>>");
- default: Q_UNREACHABLE();
- }
-}
-
-MIInstr *MIInstr::create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands)
-{
- return pool->New<MIInstr>(irNode, pool, nOperands);
-}
-
-static QString commentIndent(const QString &line)
-{
- int spacing = std::max(70 - line.length(), 1);
- return line + QString(spacing, QLatin1Char(' '));
-}
-
-static QString indent(int nr)
-{
- QString s = nr == -1 ? QString() : QString::number(nr);
- int padding = 6 - s.size();
- if (padding > 0)
- s = QString(padding, QLatin1Char(' ')) + s;
- return s;
-}
-
-MIFunction::MIFunction(Function *irFunction)
- : m_irFunction(irFunction)
-{}
-
-void MIFunction::renumberBlocks()
-{
- for (size_t i = 0, ei = m_blocks.size(); i != ei; ++i) {
- MIBlock *b = m_blocks[i];
- b->setIndex(unsigned(i));
- }
-}
-
-void MIFunction::renumberInstructions()
-{
- int pos = 0;
- for (MIBlock *b : m_blocks) {
- for (MIInstr &instr : b->instructions()) {
- pos += 2;
- instr.setPosition(pos);
- }
- }
-}
-
-void MIFunction::dump(const QString &description) const
-{
- if (!lcMI().isDebugEnabled())
- return;
-
- QString s = description + QLatin1String(":\n");
- QString name;
- if (auto n = irFunction()->v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- QString::asprintf("%p", static_cast<void *>(irFunction()->v4Function()));
- QString line = QStringLiteral("function %1 {").arg(name);
- auto loc = irFunction()->v4Function()->sourceLocation();
- s += commentIndent(line) + QStringLiteral("; %1:%2:%3\n").arg(loc.sourceFile,
- QString::number(loc.line),
- QString::number(loc.column));
- for (const MIBlock *b : blocks()) {
- line = QStringLiteral("L%1").arg(b->index());
- bool first = true;
- if (!b->arguments().empty()) {
- line += QLatin1Char('(');
- for (const MIOperand &arg : b->arguments()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += arg.debugString();
- }
- line += QLatin1Char(')');
- }
- line += QLatin1Char(':');
- line = commentIndent(line) + QStringLiteral("; preds: ");
- if (b->inEdges().isEmpty()) {
- line += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *in : b->inEdges()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += QStringLiteral("L%1").arg(in->index());
- }
- }
- s += line + QLatin1Char('\n');
- for (const MIInstr &i : b->instructions()) {
- line = indent(i.position()) + QLatin1String(": ");
- if (i.hasDestination())
- line += i.destination().debugString() + QStringLiteral(" = ");
- line += i.irNode()->operation()->debugString();
- bool first = true;
- for (const MIOperand &op : i.operands()) {
- if (first)
- first = false;
- else
- line += QLatin1Char(',');
- line += QLatin1Char(' ') + op.debugString();
- }
- line = commentIndent(line) + QStringLiteral("; node-id: %1").arg(i.irNode()->id());
- if (i.irNode()->operation()->needsBytecodeOffsets())
- line += QStringLiteral(", bytecode-offset: %1").arg(irFunction()->nodeInfo(i.irNode())->currentInstructionOffset());
- s += line + QLatin1Char('\n');
- }
- s += commentIndent(QString()) + QStringLiteral("; succs: ");
- if (b->outEdges().isEmpty()) {
- s += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *succ : b->outEdges()) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QStringLiteral("L%1").arg(succ->index());
- }
- }
- s += QLatin1Char('\n');
- }
- s += QLatin1Char('}');
-
- for (const QStringRef &line : s.splitRef('\n'))
- qCDebug(lcMI).noquote().nospace() << line;
-}
-
-unsigned MIFunction::extraJSSlots() const
-{
- uint interpreterFrameSize = CppStackFrame::requiredJSStackFrameSize(irFunction()->v4Function());
- if (m_jsSlotCount <= interpreterFrameSize)
- return 0;
- return m_jsSlotCount - interpreterFrameSize;
-}
-
-void MIFunction::setStartBlock(MIBlock *newStartBlock)
-{
- auto it = std::find(m_blocks.begin(), m_blocks.end(), newStartBlock);
- Q_ASSERT(it != m_blocks.end());
- std::swap(*m_blocks.begin(), *it);
-}
-
-void MIFunction::setStackSlotCounts(unsigned dword, unsigned qword, unsigned js)
-{
- m_vregCount = 0;
- m_dwordSlotCount = dword;
- m_qwordSlotCount = qword;
- m_jsSlotCount = js;
-}
-
-void MIFunction::verifyCFG() const
-{
- if (block(MIFunction::StartBlockIndex)->instructions().front().opcode() != Meta::Start)
- qFatal("MIFunction block 0 is not the start block");
-
- for (MIBlock *b : m_blocks) {
- for (MIBlock *in : b->inEdges()) {
- if (!in->outEdges().contains(b))
- qFatal("block %u has incoming edge from block %u, "
- "but does not appear in that block's outgoing edges",
- b->index(), in->index());
- }
- for (MIBlock *out : b->outEdges()) {
- if (!out->inEdges().contains(b))
- qFatal("block %u has outgoing edge from block %u, "
- "but does not appear in that block's incoming edges",
- b->index(), out->index());
- }
- }
-}
-
-MIBlock *MIBlock::findEdgeTo(Operation::Kind target) const
-{
- for (MIBlock *outEdge : outEdges()) {
- if (outEdge->instructions().front().opcode() == target)
- return outEdge;
- }
- return nullptr;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4mi_p.h b/src/qml/jit/qv4mi_p.h
deleted file mode 100644
index f976d1dc94..0000000000
--- a/src/qml/jit/qv4mi_p.h
+++ /dev/null
@@ -1,627 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MI_P_H
-#define QV4MI_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4operation_p.h>
-
-#include <llvm/ADT/iterator.h>
-#include <llvm/ADT/iterator_range.h>
-#include <llvm/ADT/ilist.h>
-#include <llvm/ADT/ilist_node.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// This file contains the Machine Interface (MI) data structures, on which ultimately the assembler
-// will operate:
-
-class MIFunction; // containing all basic blocks, and a reference to the IR function
-
-class MIBlock; // containing an ordered sequence of instructions
-
-class MIInstr; // containing operands, and a reference to the IR node, that indicates which
- // operation is represented by an instruction
-
-class MIOperand; // contains a description of where to get/put the input/result of an operation
-
-// A detail about the stack slots: there two stacks, the JS stack and the native stack. A frame on
-// the native stack is divided in two parts: the quad-word part and the double-word part. The
-// qword part holds 64bit values, like doubles, and pointers on 64bit architectures. The dword part
-// holds 32bit values, like int32s, booleans, and pointers on 32bit architectures. We need to know
-// the type of value a slot holds, because if we have to move it to the JS stack, we have to box it
-// correctly.
-class MIOperand final
-{
-public:
- enum Kind {
- Invalid = 0,
- Constant,
- VirtualRegister,
-
- EngineRegister,
- CppFrameRegister,
- Function,
-
- JSStackSlot,
- BoolStackSlot,
-
- JumpTarget,
- };
-
- using List = QQmlJS::FixedPoolArray<MIOperand>;
-
-public:
- MIOperand() = default;
-
- static MIOperand createConstant(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Constant;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createVirtualRegister(Node *irNode, unsigned vreg)
- {
- MIOperand op;
- op.m_kind = VirtualRegister;
- op.m_irNode = irNode;
- op.m_vreg = vreg;
- return op;
- }
-
- static MIOperand createEngineRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = EngineRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createCppFrameRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = CppFrameRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createFunction(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Function;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createJSStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = JSStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- static MIOperand createBoolStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = BoolStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- //### or name this createDeoptBlock?
- static MIOperand createJumpTarget(Node *irNode, MIBlock *targetBlock)
- {
- MIOperand op;
- op.m_kind = JumpTarget;
- op.m_irNode = irNode;
- op.m_targetBlock = targetBlock;
- return op;
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isValid() const
- { return m_kind != Invalid; }
-
- bool isConstant() const
- { return m_kind == Constant; }
-
- bool isVirtualRegister() const
- { return kind() == VirtualRegister; }
-
- bool isEngineRegister() const
- { return kind() == EngineRegister; }
-
- bool isCppFrameRegister() const
- { return kind() == CppFrameRegister; }
-
- bool isFunction() const
- { return kind() == Function; }
-
- bool isJSStackSlot() const
- { return kind() == JSStackSlot; }
-
- bool isBoolStackSlot() const
- { return kind() == BoolStackSlot; }
-
- bool isStackSlot() const
- { return isJSStackSlot() || isDWordSlot() || isQWordSlot(); }
-
- bool isJumpTarget() const
- { return kind() == JumpTarget; }
-
- Node *irNode() const
- { return m_irNode; }
-
- inline Type nodeType(MIFunction *f) const;
-
- QString debugString() const;
-
- QV4::Value constantValue() const
- {
- Q_ASSERT(isConstant());
- if (irNode()->opcode() == Meta::Undefined)
- return QV4::Value::undefinedValue();
- if (irNode()->opcode() == Meta::Empty)
- return QV4::Value::emptyValue();
- return ConstantPayload::get(*irNode()->operation())->value();
- }
-
- unsigned virtualRegister() const
- { Q_ASSERT(isVirtualRegister()); return m_vreg; }
-
- unsigned stackSlot() const
- { Q_ASSERT(isStackSlot()); return m_slot; }
-
- MIBlock *targetBlock() const
- { Q_ASSERT(isJumpTarget()); return m_targetBlock; }
-
- inline bool operator==(const MIOperand &other) const
- {
- if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- switch (kind()) {
- case MIOperand::Invalid:
- return !other.isValid();
- case MIOperand::Constant:
- return constantValue().asReturnedValue() == other.constantValue().asReturnedValue();
- case MIOperand::VirtualRegister:
- return virtualRegister() == other.virtualRegister();
- case MIOperand::JumpTarget:
- return targetBlock() == other.targetBlock();
- default:
- Q_UNREACHABLE();
- return false;
- }
- }
-
- bool isDWordSlot() const
- {
- switch (kind()) {
- case BoolStackSlot:
- return true;
- default:
- return false;
- }
- }
-
- bool isQWordSlot() const
- {
- switch (kind()) {
- //### TODO: double slots
- default:
- return false;
- }
- }
-
- bool overlaps(const MIOperand &other) const
- {
- if ((isDWordSlot() && other.isDWordSlot()) || (isQWordSlot() && other.isQWordSlot()))
- ; // fine, these are the same
- else if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- return false;
- }
-
-private:
- Node *m_irNode = nullptr;
- union {
- unsigned m_vreg;
- unsigned m_slot;
- MIBlock *m_targetBlock = nullptr;
- };
- Kind m_kind = Invalid;
-};
-
-template <typename NodeTy> struct MIInstrListParentType {};
-template <> struct MIInstrListParentType<MIInstr> { using type = MIBlock; };
-
-template <typename NodeTy> class MIInstrList;
-
-template <typename MISubClass>
-class MIInstrListTraits : public llvm::ilist_noalloc_traits<MISubClass>
-{
-protected:
- using ListTy = MIInstrList<MISubClass>;
- using iterator = typename llvm::simple_ilist<MISubClass>::iterator;
- using ItemParentClass = typename MIInstrListParentType<MISubClass>::type;
-
-public:
- MIInstrListTraits() = default;
-
-protected:
- void setListOwner(ItemParentClass *listOwner)
- { m_owner = listOwner; }
-
-private:
- ItemParentClass *m_owner = nullptr;
-
- /// getListOwner - Return the object that owns this list. If this is a list
- /// of instructions, it returns the BasicBlock that owns them.
- ItemParentClass *getListOwner() const {
- return m_owner;
- }
-
- static ListTy &getList(ItemParentClass *Par) {
- return Par->*(Par->getSublistAccess());
- }
-
- static MIInstrListTraits<MISubClass> *getSymTab(ItemParentClass *Par) {
- return Par ? toPtr(Par->getValueSymbolTable()) : nullptr;
- }
-
-public:
- void addNodeToList(MISubClass *V) { V->setParent(getListOwner()); }
- void removeNodeFromList(MISubClass *V) { V->setParent(nullptr); }
- void transferNodesFromList(MIInstrListTraits &L2, iterator first,
- iterator last);
-};
-
-template <class T>
-class MIInstrList: public llvm::iplist_impl<llvm::simple_ilist<T>, MIInstrListTraits<T>>
-{
-public:
- MIInstrList(typename MIInstrListTraits<T>::ItemParentClass *owner)
- { this->setListOwner(owner); }
-};
-
-class MIInstr final : public llvm::ilist_node_with_parent<MIInstr, MIBlock>
-{
- Q_DISABLE_COPY_MOVE(MIInstr) // heap use only!
-
-protected:
- friend class QQmlJS::MemoryPool;
- MIInstr() : m_operands(nullptr, 0) {}
-
- explicit MIInstr(Node *irNode, QQmlJS::MemoryPool *pool, unsigned nOperands)
- : m_irNode(irNode)
- , m_operands(pool, nOperands)
- {}
-
- ~MIInstr() = default;
-
-public:
- static MIInstr *create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands);
-
- MIBlock *parent() const
- { return m_parent; }
-
- MIBlock *getParent() const // for ilist_node_with_parent
- { return parent(); }
-
- void setParent(MIBlock *parent)
- { m_parent = parent; }
-
- Node *irNode() const
- { return m_irNode; }
-
- Operation::Kind opcode() const
- { return m_irNode->opcode(); }
-
- int position() const
- { return m_position; }
-
- inline void insertBefore(MIInstr *insertPos);
- inline void insertAfter(MIInstr *insertPos);
- inline MIInstrList<MIInstr>::iterator eraseFromParent();
-
- bool hasDestination() const
- { return m_destination.isValid(); }
-
- MIOperand destination() const
- { return m_destination; }
-
- void setDestination(const MIOperand &dest)
- { m_destination = dest; }
-
- const MIOperand &operand(unsigned index) const
- { return m_operands.at(index); }
-
- void setOperand(unsigned index, const MIOperand &op)
- { m_operands.at(index) = op; }
-
- MIOperand &operand(unsigned index)
- { return m_operands.at(index); }
-
- const MIOperand::List &operands() const
- { return m_operands; }
-
- MIOperand::List &operands()
- { return m_operands; }
-
-private:
- friend MIFunction;
- void setPosition(int newPosition)
- { m_position = newPosition; }
-
-private:
- MIBlock *m_parent = nullptr;
- Node *m_irNode = nullptr;
- int m_position = -1;
- MIOperand m_destination;
- MIOperand::List m_operands;
-};
-
-class MIBlock final
-{
- Q_DISABLE_COPY_MOVE(MIBlock)
-
-public:
- using Index = unsigned;
- enum : Index { InvalidIndex = std::numeric_limits<Index>::max() };
-
- using MIInstructionList = MIInstrList<MIInstr>;
-
- using InEdges = QVarLengthArray<MIBlock *, 4>;
- using OutEdges = QVarLengthArray<MIBlock *, 2>;
-
-protected:
- friend MIFunction;
- explicit MIBlock(Index index)
- : m_instructions(this),
- m_index(index)
- {}
-
- void setIndex(Index newIndex)
- { m_index = newIndex; }
-
-public:
- ~MIBlock() = default;
-
- const MIInstructionList &instructions() const
- { return m_instructions; }
-
- MIInstructionList &instructions()
- { return m_instructions; }
-
- static MIInstructionList MIBlock::*getSublistAccess(MIInstr * = nullptr)
- { return &MIBlock::m_instructions; }
-
- void addArgument(MIOperand &&arg)
- { m_arguments.push_back(arg); }
-
- const std::vector<MIOperand> &arguments() const
- { return m_arguments; }
-
- std::vector<MIOperand> &arguments()
- { return m_arguments; }
-
- void clearArguments()
- { m_arguments.resize(0); }
-
- const InEdges &inEdges() const
- { return m_inEdges; }
-
- void addInEdge(MIBlock *edge)
- { m_inEdges.append(edge); }
-
- const OutEdges &outEdges() const
- { return m_outEdges; }
-
- void addOutEdge(MIBlock *edge)
- { m_outEdges.append(edge); }
-
- Index index() const
- { return m_index; }
-
- MIBlock *findEdgeTo(Operation::Kind target) const;
-
- bool isDeoptBlock() const
- { return m_isDeoptBlock; }
-
- void markAsDeoptBlock()
- { m_isDeoptBlock = true; }
-
-private:
- std::vector<MIOperand> m_arguments;
- MIInstructionList m_instructions;
- InEdges m_inEdges;
- OutEdges m_outEdges;
- Index m_index;
- bool m_isDeoptBlock = false;
-};
-
-class MIFunction final
-{
- Q_DISABLE_COPY_MOVE(MIFunction)
-
-public:
- static constexpr MIBlock::Index StartBlockIndex = 0;
-
-public:
- MIFunction(Function *irFunction);
- ~MIFunction()
- { qDeleteAll(m_blocks); }
-
- Function *irFunction() const
- { return m_irFunction; }
-
- void setStartBlock(MIBlock *newStartBlock);
- void renumberBlocks();
- void renumberInstructions();
-
- void dump(const QString &description) const;
-
- size_t blockCount() const
- { return blocks().size(); }
-
- MIBlock *block(MIBlock::Index index) const
- { return m_blocks[index]; }
-
- const std::vector<MIBlock *> &blocks() const
- { return m_blocks; }
-
- MIBlock *addBlock()
- {
- auto *b = new MIBlock(unsigned(m_blocks.size()));
- m_blocks.push_back(b);
- return b;
- }
-
- void setBlockOrder(const std::vector<MIBlock *> &newSequence)
- { m_blocks = newSequence; }
-
- unsigned vregCount() const
- { return m_vregCount; }
-
- void setVregCount(unsigned vregCount)
- { m_vregCount = vregCount; }
-
- unsigned dwordSlotCount() const
- { return m_dwordSlotCount; }
-
- unsigned qwordSlotCount() const
- { return m_qwordSlotCount; }
-
- unsigned jsSlotCount() const
- { return m_jsSlotCount; }
-
- unsigned extraJSSlots() const;
-
- void setStackSlotCounts(unsigned dword, unsigned qword, unsigned js);
-
- void verifyCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- std::vector<MIBlock *> m_blocks;
- unsigned m_vregCount = 0;
- unsigned m_dwordSlotCount = 0;
- unsigned m_qwordSlotCount = 0;
- unsigned m_jsSlotCount = 0;
-};
-
-Type MIOperand::nodeType(MIFunction *f) const
-{
- return f->irFunction()->nodeInfo(irNode())->type();
-}
-
-inline uint qHash(const MIOperand &key, uint seed)
-{
- uint h = ::qHash(key.kind(), seed);
- switch (key.kind()) {
- case MIOperand::VirtualRegister:
- h ^= key.virtualRegister();
- break;
- case MIOperand::BoolStackSlot: Q_FALLTHROUGH();
- case MIOperand::JSStackSlot:
- h ^= key.stackSlot();
- break;
- default:
- qFatal("%s: cannot hash %s", Q_FUNC_INFO, key.debugString().toUtf8().constData());
- }
- return h;
-}
-
-void MIInstr::insertBefore(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(insertPos->getIterator(), this);
-}
-
-void MIInstr::insertAfter(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(++insertPos->getIterator(), this);
-}
-
-MIInstrList<MIInstr>::iterator MIInstr::eraseFromParent()
-{
- auto p = parent();
- setParent(nullptr);
- return p->instructions().erase(getIterator());
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MI_P_H
diff --git a/src/qml/jit/qv4miblockset_p.h b/src/qml/jit/qv4miblockset_p.h
deleted file mode 100644
index 5f814b99e0..0000000000
--- a/src/qml/jit/qv4miblockset_p.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MIBLOCKSET_P_H
-#define QV4MIBLOCKSET_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class MIBlockSet
-{
- using Flags = BitVector;
-
- QVarLengthArray<MIBlock::Index, 8> blockNumbers;
- Flags *blockFlags = nullptr;
- MIFunction *function = nullptr;
- enum { MaxVectorCapacity = 8 };
-
-public:
- class const_iterator;
- friend class const_iterator;
-
-public:
- MIBlockSet(MIFunction *f = nullptr)
- {
- if (f)
- init(f);
- }
-
- MIBlockSet(MIBlockSet &&other) noexcept
- {
- std::swap(blockNumbers, other.blockNumbers);
- std::swap(blockFlags, other.blockFlags);
- std::swap(function, other.function);
- }
-
- MIBlockSet(const MIBlockSet &other)
- : function(other.function)
- {
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- }
-
- MIBlockSet &operator=(const MIBlockSet &other)
- {
- if (blockFlags) {
- delete blockFlags;
- blockFlags = nullptr;
- }
- function = other.function;
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- return *this;
- }
-
- MIBlockSet &operator=(MIBlockSet &&other) noexcept
- {
- if (&other != this) {
- std::swap(blockNumbers, other.blockNumbers);
-
- delete blockFlags;
- blockFlags = other.blockFlags;
- other.blockFlags = nullptr;
-
- function = other.function;
- }
- return *this;
- }
-
- ~MIBlockSet()
- {
- delete blockFlags;
- }
-
- void init(MIFunction *f)
- {
- Q_ASSERT(!function);
- Q_ASSERT(f);
- function = f;
- }
-
- bool empty() const;
-
- void insert(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->setBit(bb->index());
- return;
- }
-
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- if (blockNumber == bb->index())
- return;
- }
-
- if (blockNumbers.size() == MaxVectorCapacity) {
- blockFlags = new Flags(int(function->blockCount()), false);
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- blockFlags->setBit(int(blockNumber));
- }
- blockNumbers.clear();
- blockFlags->setBit(int(bb->index()));
- } else {
- blockNumbers.append(bb->index());
- }
- }
-
- void remove(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->clearBit(bb->index());
- return;
- }
-
- for (int i = 0; i < blockNumbers.size(); ++i) {
- if (blockNumbers[i] == bb->index()) {
- blockNumbers.remove(i);
- return;
- }
- }
- }
-
- const_iterator begin() const;
- const_iterator end() const;
-
- void collectValues(std::vector<MIBlock *> &bbs) const;
-
- bool contains(MIBlock *bb) const
- {
- Q_ASSERT(function);
-
- if (blockFlags)
- return blockFlags->at(bb->index());
-
- for (unsigned int blockNumber : blockNumbers) {
- if (blockNumber == bb->index())
- return true;
- }
-
- return false;
- }
-};
-
-class MIBlockSet::const_iterator
-{
- const MIBlockSet &set;
- // ### These two members could go into a union, but clang won't compile
- // (https://codereview.qt-project.org/#change,74259)
- QVarLengthArray<MIBlock::Index, 8>::const_iterator numberIt;
- MIBlock::Index flagIt;
-
- friend class MIBlockSet;
- const_iterator(const MIBlockSet &set, bool end)
- : set(set)
- {
- if (end || !set.function) {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.end();
- else
- flagIt = set.blockFlags->size();
- } else {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.begin();
- else
- findNextWithFlags(0);
- }
- }
-
- void findNextWithFlags(int start)
- {
- flagIt = MIBlock::Index(set.blockFlags->findNext(start, true, /*wrapAround = */false));
- Q_ASSERT(flagIt <= MIBlock::Index(set.blockFlags->size()));
- }
-
-public:
- MIBlock *operator*() const
- {
- if (!set.blockFlags)
- return set.function->block(*numberIt);
-
- Q_ASSERT(flagIt <= set.function->blockCount());
- return set.function->block(flagIt);
-
- }
-
- bool operator==(const const_iterator &other) const
- {
- if (&set != &other.set)
- return false;
- if (!set.blockFlags)
- return numberIt == other.numberIt;
- return flagIt == other.flagIt;
- }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- {
- if (!set.blockFlags)
- ++numberIt;
- else
- findNextWithFlags(flagIt + 1);
-
- return *this;
- }
-};
-
-inline bool MIBlockSet::empty() const
-{ return begin() == end(); }
-
-inline MIBlockSet::const_iterator MIBlockSet::begin() const
-{ return const_iterator(*this, false); }
-
-inline MIBlockSet::const_iterator MIBlockSet::end() const
-{ return const_iterator(*this, true); }
-
-inline void MIBlockSet::collectValues(std::vector<MIBlock *> &bbs) const
-{
- Q_ASSERT(function);
-
- for (auto it : *this)
- bbs.push_back(it);
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MIBLOCKSET_P_H
diff --git a/src/qml/jit/qv4node.cpp b/src/qml/jit/qv4node.cpp
deleted file mode 100644
index e059e9fef6..0000000000
--- a/src/qml/jit/qv4node.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4node_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Node *Node::create(Node::MemoryPool *pool, Node::Id id, const Operation *op, size_t nInputs,
- Node *const *inputs, bool inputsAreExtensible)
-{
- size_t capacity = nInputs;
- if (inputsAreExtensible)
- capacity += 3;
-
- Node *node = new (pool->allocate(sizeof(Node))) Node(pool, id, op, unsigned(nInputs),
- int(capacity));
- for (uint i = 0; i < capacity; ++i)
- new (&node->m_inputs[int(i)]) Use(node);
- for (size_t i = 0; i < nInputs; ++i) {
- Q_ASSERT(inputs[i] != nullptr);
- node->replaceInput(unsigned(i), inputs[i]);
- }
-
- return node;
-}
-
-void Node::addInput(MemoryPool *pool, Node *in)
-{
- Q_ASSERT(in);
- ++m_nInputs;
- if (m_nInputs >= unsigned(m_inputs.size())) {
- QQmlJS::FixedPoolArray<Use> oldInputs = m_inputs;
- m_inputs = QQmlJS::FixedPoolArray<Use>(pool, int(m_nInputs + 3));
- for (Use &input : m_inputs)
- new (&input) Use(this);
- for (int i = 0, ei = oldInputs.size(); i != ei; ++i) {
- Node *in = oldInputs[i].m_input;
- oldInputs[i].set(nullptr);
- m_inputs[i].set(in);
- }
- }
- m_inputs.at(int(m_nInputs - 1)).set(in);
-}
-
-void Node::removeInput(unsigned index)
-{
- Q_ASSERT(index < inputCount());
- for (unsigned i = index, ei = inputCount(); i < ei - 1; ++i)
- replaceInput(i, input(i + 1));
- trimInputCount(inputCount() - 1);
-}
-
-void Node::removeInputs(unsigned start, unsigned count)
-{
- for (unsigned idx = start; idx < start + count; ++idx)
- m_inputs.at(int(idx)).set(nullptr);
-}
-
-void Node::removeAllInputs()
-{
- removeInputs(0, inputCount());
-}
-
-void Node::trimInputCount(unsigned newCount)
-{
- unsigned currentCount = inputCount();
- if (newCount == currentCount)
- return;
- Q_ASSERT(newCount < currentCount);
- removeInputs(newCount, currentCount - newCount);
- m_nInputs = newCount;
-}
-
-void Node::removeExceptionHandlerUse()
-{
- for (Use* use = m_firstUse; use; use = use->m_next) {
- if (use->m_input->opcode() == Meta::OnException) {
- use->set(nullptr);
- break;
- }
- }
-}
-
-void Node::insertInput(Node::MemoryPool *pool, unsigned index, Node *newInput)
-{
- Q_ASSERT(index < inputCount());
- addInput(pool, input(inputCount() - 1));
- for (unsigned i = inputCount() - 1; i > index; --i)
- replaceInput(i, input(i - 1));
- replaceInput(index, newInput);
-}
-
-void Node::replaceAllUsesWith(Node *replacement)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const unsigned inIdx = use->inputIndex();
- use->user()->replaceInput(inIdx, replacement);
- use = next;
- }
-}
-
-void Node::replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const Operation *inOp = use->user()->operation();
- const unsigned inIdx = use->inputIndex();
- if (inIdx < inOp->valueInputCount())
- use->user()->replaceInput(inIdx, newValueInput);
- else if (inIdx < inOp->indexOfFirstControl())
- use->user()->replaceInput(inIdx, newEffectInput);
- else
- use->user()->replaceInput(inIdx, newControlInput);
- use = next;
- }
-}
-
-Node *Node::firstValueUse()
-{
- for (auto it = uses().begin(), eit = uses().end(); it != eit; ++it) {
- if (it.isUsedAsValue())
- return *it;
- }
- return nullptr;
-}
-
-Node::Node(MemoryPool *pool, Node::Id id, const Operation *op, unsigned nInputs, int capacity)
- : m_op(op)
- , m_inputs(pool, capacity)
- , m_nInputs(nInputs)
- , m_id(id)
-{
-}
-
-NodeWorkList::NodeWorkList(const Graph *g)
- : m_nodeState(g->nodeCount(), Unvisited)
-{ m_worklist.reserve(64); }
-
-void NodeWorkList::reset()
-{
- std::fill(m_nodeState.begin(), m_nodeState.end(), Unvisited);
- m_worklist.clear();
- if (m_worklist.capacity() < 64)
- m_worklist.reserve(64);
-}
-
-NodeCollector::NodeCollector(const Graph *g, bool collectUses, bool skipFramestate)
-{
- markReachable(g->endNode());
- for (size_t i = 0; i < m_reachable.size(); ++i) { // _reachable.size() is on purpose!
- Node *n = m_reachable.at(i);
- for (auto input : n->inputs()) {
- if (input == nullptr)
- continue;
- if (isReachable(input->id()))
- continue;
- if (skipFramestate && input->opcode() == Meta::FrameState)
- continue;
- markReachable(input);
- }
-
- if (collectUses) {
- for (Node *use : n->uses()) {
- if (use && !isReachable(use->id()))
- markReachable(use);
- }
- }
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4node_p.h b/src/qml/jit/qv4node_p.h
deleted file mode 100644
index 76065fb1bc..0000000000
--- a/src/qml/jit/qv4node_p.h
+++ /dev/null
@@ -1,626 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4NODE_P_H
-#define QV4NODE_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4operation_p.h>
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Use
-{
- Q_DISABLE_COPY_MOVE(Use)
-
-public:
- Use(Node *user)
- : m_user(user)
- {}
-
- ~Use()
- {
- if (m_input)
- removeFromList();
- }
-
- operator Node *() const { return m_input; }
- Node *input() const { return m_input; }
- Node *user() const { return m_user; }
-
- inline void set(Node *newInput);
-
- void validate() const
- {
- Q_ASSERT(m_user);
- if (m_input) {
- if (m_prev != nullptr)
- Q_ASSERT(*m_prev == this);
- if (m_next) {
- Q_ASSERT(m_next->m_input == m_input);
- Q_ASSERT(m_next->m_prev == &m_next);
- m_next->validate();
- }
- }
- }
-
- inline int inputIndex() const;
-
-protected:
- friend class Node;
-
- void addToList(Use **list) {
- validate();
- m_next = *list;
- if (m_next)
- m_next->m_prev = &m_next;
- m_prev = list;
- *list = this;
- validate();
- }
-
- void removeFromList() {
- validate();
- Use **newPrev = m_prev;
- *newPrev = m_next;
- m_prev = nullptr;
- if (m_next)
- m_next->m_prev = newPrev;
- m_next = nullptr;
- m_input = nullptr;
- validate();
- }
-
-private:
- Node *m_input = nullptr;
- Node *m_user = nullptr;
- Use *m_next = nullptr;
- Use **m_prev = nullptr;
-};
-
-// A node represents an calculation, action, or marker in the graph. Each node has an operation,
-// input dependencies and uses. The operation indicates what kind of node it is, e.g.: JSAdd,
-// Constant, Region, and so on. Two nodes can have the same operation, but different inputs.
-// For example, the expressions 1 + 2 and 3 + 4 will each have a node with an JSAdd operation
-// (which is exactly the same operation for both nodes), but the nodes have different inputs (1, and
-// 2 in the first expression, while the second operation has 3 and 4 as inputs).
-class Node final
-{
- Q_DISABLE_COPY_MOVE(Node)
-
-public:
- using Id = uint32_t;
- using MemoryPool = QQmlJS::MemoryPool;
- class Inputs;
-
-public:
- static Node *create(MemoryPool *pool, Id id, const Operation *op, size_t nInputs,
- Node * const *inputs, bool inputsAreExtensible = false);
- ~Node() = delete;
-
- inline bool isDead() const;
- inline void kill();
-
- Id id() const { return m_id; }
-
- const Operation *operation() const
- { return m_op; }
-
- void setOperation(const Operation *op)
- { m_op = op; }
-
- Operation::Kind opcode() const
- { return operation()->kind(); }
-
- inline Inputs inputs() const;
- void addInput(MemoryPool *pool, Node *in);
- void removeInput(unsigned index);
- void removeInputs(unsigned start, unsigned count);
- void removeAllInputs();
- uint32_t inputCount() const
- { return m_nInputs; }
- void trimInputCount(unsigned newCount);
-
- void removeExceptionHandlerUse();
-
- Node *input(unsigned idx) const
- {
- Q_ASSERT(idx < inputCount());
- return m_inputs.at(idx);
- }
-
- Node *effectInput(unsigned effectIndex = 0) const
- {
- if (operation()->effectInputCount() == 0)
- return nullptr;
- Q_ASSERT(effectIndex < operation()->effectInputCount());
- return input(operation()->indexOfFirstEffect() + effectIndex);
- }
-
- Node *controlInput(unsigned controlIndex = 0) const
- {
- if (operation()->controlInputCount() == 0)
- return nullptr;
- Q_ASSERT(controlIndex < operation()->controlInputCount());
- return input(operation()->indexOfFirstControl() + controlIndex);
- }
-
- Node *frameStateInput() const
- {
- if (operation()->hasFrameStateInput())
- return input(operation()->indexOfFrameStateInput());
- return nullptr;
- }
-
- void setFrameStateInput(Node *newFramestate)
- {
- if (operation()->hasFrameStateInput())
- replaceInput(operation()->indexOfFrameStateInput(), newFramestate);
- }
-
- void insertInput(MemoryPool *pool, unsigned index, Node *newInput);
-
- void replaceInput(Node *oldIn, Node *newIn)
- {
- for (unsigned i = 0, ei = inputCount(); i != ei; ++i) {
- if (input(i) == oldIn)
- replaceInput(i, newIn);
- }
- }
-
- void replaceInput(unsigned idx, Node *newIn)
- {
- m_inputs[idx].set(newIn);
- }
-
- class Uses
- {
- public:
- explicit Uses(Node *node)
- : m_node(node)
- {}
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool isEmpty() const;
-
- private:
- Node *m_node;
- };
-
- Uses uses() { return Uses(this); }
- bool hasUses() const { return m_firstUse != nullptr; }
- unsigned useCount() const
- {
- unsigned cnt = 0;
- for (Use *it = m_firstUse; it; it = it->m_next)
- ++cnt;
- return cnt;
- }
- void replaceAllUsesWith(Node *replacement);
- void replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput);
-
- Node *firstValueUse();
-
-private: // types and utility methods
- friend class Use;
- Node(MemoryPool *pool, Id id, const Operation *op, unsigned nInputs, int capacity);
-
-private: // fields
- Use *m_firstUse = nullptr;
- const Operation *m_op = nullptr;
- QQmlJS::FixedPoolArray<Use> m_inputs;
- unsigned m_nInputs = 0;
- Id m_id = 0;
-};
-
-void Use::set(Node *newInput)
-{
- if (m_input)
- removeFromList();
- m_input = newInput;
- if (newInput)
- addToList(&newInput->m_firstUse);
-}
-
-class Node::Inputs final
-{
-public:
- using value_type = Node *;
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool empty() const
- { return m_nInputs == 0; }
-
- unsigned count() const
- { return m_nInputs; }
-
- explicit Inputs(const Use *inputs, unsigned nInputs)
- : m_inputs(inputs), m_nInputs(nInputs)
- {}
-
-private:
- const Use *m_inputs = nullptr;
- unsigned m_nInputs = 0;
-};
-
-class Node::Inputs::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using value_type = Node *;
- using pointer = const value_type *;
- using reference = value_type &;
-
- Node *operator*() const
- { return m_inputs->m_input; }
-
- bool operator==(const const_iterator &other) const
- { return m_inputs == other.m_inputs; }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- { ++m_inputs; return *this; }
-
- const_iterator& operator+=(difference_type offset)
- { m_inputs += offset; return *this; }
-
- const_iterator operator+(difference_type offset) const
- { return const_iterator(m_inputs + offset); }
-
- difference_type operator-(const const_iterator &other) const
- { return m_inputs - other.m_inputs; }
-
-private:
- friend class Node::Inputs;
-
- explicit const_iterator(const Use *inputs)
- : m_inputs(inputs)
- {}
-
- const Use *m_inputs;
-};
-
-Node::Inputs::const_iterator Node::Inputs::begin() const
-{ return const_iterator(m_inputs); }
-
-Node::Inputs::const_iterator Node::Inputs::end() const
-{ return const_iterator(m_inputs + m_nInputs); }
-
-Node::Inputs Node::inputs() const
-{
- return Inputs(m_inputs.begin(), m_nInputs);
-}
-
-class Node::Uses::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = int;
- using value_type = Node *;
- using pointer = Node **;
- using reference = Node *&;
-
- Node *operator*() const
- { return m_current->user(); }
-
- bool operator==(const const_iterator &other) const
- { return other.m_current == m_current; }
-
- bool operator!=(const const_iterator &other) const
- { return other.m_current != m_current; }
-
- const_iterator &operator++()
- { m_current = m_next; setNext(); return *this; }
-
- unsigned inputIndex() const
- { return m_current->inputIndex(); }
-
- bool isUsedAsValue() const
- { return inputIndex() < operator*()->operation()->valueInputCount(); }
-
- bool isUsedAsControl() const
- { return operator*()->operation()->indexOfFirstControl() <= inputIndex(); }
-
-private:
- friend class Node::Uses;
-
- const_iterator() = default;
-
- explicit const_iterator(Node* node)
- : m_current(node->m_firstUse)
- { setNext(); }
-
- void setNext()
- {
- if (m_current)
- m_next = m_current->m_next;
- else
- m_next = nullptr;
- }
-
-private:
- Use *m_current = nullptr;
- Use *m_next = nullptr;
-};
-
-Node::Uses::const_iterator Node::Uses::begin() const
-{ return const_iterator(this->m_node); }
-
-Node::Uses::const_iterator Node::Uses::end() const
-{ return const_iterator(); }
-
-int Use::inputIndex() const
-{
- if (!m_user)
- return -1;
- return int(this - m_user->m_inputs.begin());
-}
-
-bool Node::isDead() const
-{
- Inputs in = inputs();
- return !in.empty() && *in.begin() == nullptr;
-}
-
-void Node::kill()
-{
- removeAllInputs();
-}
-
-class NodeWorkList final
-{
- enum State: uint8_t {
- Unvisited = 0,
- Queued,
- Visited,
- };
-
-public:
- NodeWorkList(const Graph *g);
-
- void reset();
-
- bool enqueue(Node *n)
- {
- State &s = nodeState(n);
- if (s == Queued || s == Visited)
- return false;
-
- m_worklist.push_back(n);
- s = Queued;
- return true;
- }
-
- void enqueue(const std::vector<Node *> &nodes)
- {
- m_worklist.insert(m_worklist.end(), nodes.begin(), nodes.end());
- for (Node *n : nodes)
- nodeState(n) = Queued;
- }
-
- void reEnqueue(Node *n)
- {
- if (!n)
- return;
- State &s = nodeState(n);
- if (s == Queued)
- return;
- s = Queued;
- m_worklist.push_back(n);
- }
-
- void enqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- enqueue(input);
- }
-
- void reEnqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- reEnqueue(input);
- }
-
- void enqueueValueInputs(Node *n)
- {
- for (unsigned i = 0, ei = n->operation()->valueInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueEffectInputs(Node *n)
- {
- for (unsigned i = n->operation()->indexOfFirstEffect(), ei = n->operation()->effectInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueAllUses(Node *n)
- {
- for (Node *use : n->uses())
- enqueue(use);
- }
-
- Node *dequeueNextNodeForVisiting()
- {
- while (!m_worklist.empty()) {
- Node *n = m_worklist.back();
- m_worklist.pop_back();
- State &s = nodeState(n);
- Q_ASSERT(s == Queued);
- s = Visited;
- return n;
- }
-
- return nullptr;
- }
-
- bool isVisited(Node *n) const
- { return nodeState(n) == Visited; }
-
- bool isEmpty() const
- { return m_worklist.empty(); }
-
- QString status(Node *n) const
- {
- QString s = QStringLiteral("status for node %1: ").arg(n->id());
- switch (nodeState(n)) {
- case Queued: s += QLatin1String("queued"); break;
- case Visited: s += QLatin1String("visited"); break;
- case Unvisited: s += QLatin1String("unvisited"); break;
- }
- return s;
- }
-
-private:
- State &nodeState(Node *n)
- {
- const unsigned position(n->id());
- if (position >= m_nodeState.size())
- m_nodeState.resize(position + 1, Unvisited);
-
- return m_nodeState[position];
- }
-
- State nodeState(Node *n) const
- { return m_nodeState[unsigned(n->id())]; }
-
-private:
- std::vector<Node *> m_worklist;
- std::vector<State> m_nodeState;
-};
-
-class NodeInfo
-{
-public:
- enum { NoInstructionOffset = -1 };
-
-public:
- NodeInfo() = default;
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- int currentInstructionOffset() const
- { return m_currentInstructionOffset; }
-
- int nextInstructionOffset() const
- { return m_nextInstructionOffset; }
-
- void setBytecodeOffsets(int current, int next)
- {
- Q_ASSERT(current != NoInstructionOffset);
- Q_ASSERT(next != NoInstructionOffset);
- m_currentInstructionOffset = current;
- m_nextInstructionOffset = next;
- }
-
-private:
- Type m_type;
- int m_currentInstructionOffset = NoInstructionOffset;
- int m_nextInstructionOffset = NoInstructionOffset;
-};
-
-class NodeCollector
-{
-public:
- NodeCollector(const Graph *g, bool collectUses = false, bool skipFramestate = false);
-
- const std::vector<Node *> &reachable() const
- { return m_reachable; }
-
- void sortById()
- {
- std::sort(m_reachable.begin(), m_reachable.end(), [](Node *n1, Node *n2) {
- return n1->id() < n2->id();
- });
- }
-
- bool isReachable(Node::Id nodeId) const
- {
- if (nodeId >= Node::Id(m_isReachable.size()))
- return false;
- return m_isReachable.at(int(nodeId));
- }
-
- void markReachable(Node *node)
- {
- auto nodeId = node->id();
- m_reachable.push_back(node);
- if (nodeId >= Node::Id(m_isReachable.size()))
- m_isReachable.resize(int(nodeId + 1), false);
- m_isReachable.setBit(int(nodeId));
- }
-
-private:
- std::vector<Node *> m_reachable;
- BitVector m_isReachable;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4NODE_P_H
diff --git a/src/qml/jit/qv4operation.cpp b/src/qml/jit/qv4operation.cpp
deleted file mode 100644
index acd5328fd0..0000000000
--- a/src/qml/jit/qv4operation.cpp
+++ /dev/null
@@ -1,770 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4operation_p.h"
-#include "qv4runtimesupport_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-OperationBuilder::OperationBuilder(QQmlJS::MemoryPool *graphPool)
- : m_graphPool(graphPool)
-{}
-
-OperationBuilder *OperationBuilder::create(QQmlJS::MemoryPool *pool)
-{
- return pool->New<OperationBuilder>(pool);
-}
-
-Operation *OperationBuilder::getConstant(Value v)
-{
- Type t;
- switch (v.type()) {
- case Value::Undefined_Type: t = Type::undefinedType(); break;
- case Value::Integer_Type: t = Type::int32Type(); break;
- case Value::Boolean_Type: t = Type::booleanType(); break;
- case Value::Null_Type: t = Type::nullType(); break;
- case Value::Double_Type: t = Type::doubleType(); break;
- case Value::Managed_Type: t = Type::objectType(); break;
- default:
- if (v.isEmpty())
- t = Type::emptyType();
- else
- Q_UNREACHABLE();
- }
- return OperationWithPayload<ConstantPayload>::create(
- m_graphPool, Meta::Constant, 0, 0, 0, 1, 0, 0, t, Operation::NoFlags,
- ConstantPayload(v));
-}
-
-Operation *OperationBuilder::getParam(unsigned index, const Function::StringId name)
-{
- return OperationWithPayload<ParameterPayload>::create(m_graphPool, Meta::Parameter,
- 1, 0, 0,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags,
- ParameterPayload(index, name));
-}
-
-Operation *OperationBuilder::getRegion(unsigned nControlInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Region,
- 0, 0, uint16_t(nControlInputs),
- 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getPhi(unsigned nValueInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Phi,
- uint16_t(nValueInputs), 0, 1,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEffectPhi(unsigned nEffectInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::EffectPhi,
- 0, uint16_t(nEffectInputs), 1,
- 0, 1, 0,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getUnwindDispatch(unsigned nContinuations, int unwindHandlerOffset,
- int fallthroughSuccessor)
-{
- return OperationWithPayload<UnwindDispatchPayload>::create(
- m_graphPool, Meta::UnwindDispatch,
- 0, 1, 1, 0, nContinuations, nContinuations,
- Type(), Operation::NoFlags,
- UnwindDispatchPayload(unwindHandlerOffset,
- fallthroughSuccessor));
-}
-
-Operation *OperationBuilder::getHandleUnwind(int unwindHandlerOffset)
-{
- return OperationWithPayload<HandleUnwindPayload>::create(m_graphPool, Meta::HandleUnwind,
- 0, 1, 1, 0, 1, 1,
- Type(), Operation::NoFlags,
- HandleUnwindPayload(unwindHandlerOffset));
-}
-
-Operation *OperationBuilder::getFrameState(uint16_t frameSize)
-{
- if (m_opFrameState == nullptr)
- m_opFrameState = Operation::create(m_graphPool, Meta::FrameState,
- frameSize, 0, 0, 0, 0, 1,
- Type(), Operation::NoFlags);
- else
- Q_ASSERT(frameSize == m_opFrameState->valueInputCount());
-
- return m_opFrameState;
-}
-
-Operation *OperationBuilder::getStart(uint16_t outputCount)
-{
- return Operation::create(m_graphPool, Meta::Start,
- 0, 0, 0,
- outputCount, 1, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEnd(uint16_t controlInputCount)
-{
- return Operation::create(m_graphPool, Meta::End,
- 0, 0, controlInputCount,
- 0, 0, 0,
- Type(), Operation::NoFlags);
-}
-
-inline Operation *createOperation(Operation::Kind kind, QQmlJS::MemoryPool *staticPool)
-{
- auto get = [&](uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type (*typeCreator)(), uint8_t flags) {
- return Operation::create(staticPool, kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount, typeCreator(),
- flags);
- };
-
- using K = Operation::Kind;
- using F = Operation::Flags;
- const auto none = &Type::noneType;
- const auto any = &Type::anyType;
- const auto number = &Type::numberType;
- const auto boolean = &Type::booleanType;
-
- switch (kind) {
- case K::Undefined:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Undefined, 0, 0, 0, 1, 0, 0, Type::undefinedType(), F::NoFlags,
- ConstantPayload(Primitive::undefinedValue()));
- case K::Empty:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Constant, 0, 0, 0, 1, 0, 0, Type::emptyType(), Operation::NoFlags,
- ConstantPayload(Primitive::emptyValue()));
- case K::Engine: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::CppFrame: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Function: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Jump: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::Return: return get(1, 1, 1, 0, 0, 1, none, F::NoFlags);
- case K::Branch: return get(1, 0, 1, 0, 0, 2, none, F::HasFrameStateInput | F::NeedsBytecodeOffsets);
- case K::IfTrue: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::IfFalse: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::SelectOutput: return get(3, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::Throw: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::OnException: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::ThrowReferenceError: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::UnwindToLabel: return get(2, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::LoadRegExp: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::ScopedLoad: return get(2, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::ScopedStore: return get(3, 1, 0, 0, 1, 0, none, F::NoFlags);
- case K::JSLoadElement: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSGetLookup: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreElement: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupStrict: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupSloppy: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreProperty: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadGlobalLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreNameSloppy: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreNameStrict: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadSuperProperty: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreSuperProperty: return get(2, 1, 1, 0, 1, 2, any, F::CanThrow);
- case K::JSLoadClosure: return get(1, 1, 0, 1, 1, 0, any, F::Pure);
- case K::JSGetIterator: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNext: return get(2, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNextForYieldStar: return get(3, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- case K::JSIteratorClose: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSIn: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSInstanceOf: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::QMLLoadQmlContextPropertyLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSStrictEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
-
- case K::JSAdd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSSubtract: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSMultiply: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSDivide: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSModulo: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSExponentiate: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
-
- case K::JSBitAnd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitOr: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitXor: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSUnsignedShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftLeft: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSNegate: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSToNumber: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::Alloca: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- //### it is questionable if VAAlloc/VASeal need effect edges
- case K::VAAlloc: return get(1, 1, 0, 1, 1, 0, none, F::NoFlags);
-
- case K::VAStore: return get(3, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- case K::JSTypeofName: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSTypeofValue: return get(1, 0, 0, 1, 0, 0, any, F::Pure);
- case K::JSDeclareVar: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDestructureRestElement: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSCreateCallContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateCatchContext: return get(2, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCreateWithContext: return get(1, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::JSCreateBlockContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCloneBlockContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateScriptContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSPopScriptContext: return get(0, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::PopContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
-
- case K::JSThisToObject: return get(1, 1, 1, 0, 1, 2, any, F::NoFlags);
- case K::JSCreateMappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateUnmappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateRestParameter: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::JSLoadSuperConstructor: return get(1, 1, 1, 1, 1, 2, any, F::NoFlags);
- case K::JSThrowOnNullOrUndefined: return get(1, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSGetTemplateObject: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::StoreThis: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
-
- case K::GetException: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::SetException: return get(1, 1, 0, 0, 1, 0, any, F::NoFlags);
-
- case K::ToObject: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::ToBoolean: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::IsEmpty: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::BooleanNot: return get(1, 0, 0, 1, 0, 0, boolean, F::NoFlags);
- case K::HasException: return get(1, 1, 0, 1, 1, 0, boolean, F::NoFlags);
-
- case K::Swap: return get(0, 0, 0, 0, 0, 0, none, F::NoFlags);
- case K::Move: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- default: // Non-static operations:
- return nullptr;
- }
-}
-
-Operation *OperationBuilder::staticOperation(Operation::Kind kind)
-{
- static QAtomicPointer<Operation *> ops;
- if (Operation **staticOps = ops.load())
- return staticOps[kind];
-
- static QAtomicInt initializing = 0;
- if (initializing.testAndSetOrdered(0, 1)) {
- // This is safe now, because we can only run this piece of code once during the life time
- // of the application as we can only change initializing from 0 to 1 once.
- Operation **staticOps = new Operation *[Meta::KindsEnd];
- static QQmlJS::MemoryPool pool;
- for (int i = 0; i < Meta::KindsEnd; ++i)
- staticOps[i] = createOperation(Operation::Kind(i), &pool);
- bool success = ops.testAndSetOrdered(nullptr, staticOps);
- Q_ASSERT(success);
- } else {
- // Unfortunately we need to busy wait now until the other thread finishes the static
- // initialization;
- while (!ops.load()) {}
- }
-
- return ops.load()[kind];
-}
-
-Operation *OperationBuilder::getJSVarArgsCall(Operation::Kind kind, uint16_t argc)
-{
- return Operation::create(m_graphPool, kind,
- argc, 1, 1, 1, 1, 2,
- Type::anyType(), Operation::CanThrow);
-}
-
-Operation *OperationBuilder::getJSTailCall(uint16_t argc)
-{
- return Operation::create(m_graphPool, Meta::JSTailCall,
- argc, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getTailCall()
-{
- // special varargs call, takes cppframe, engine, func, thisObject, argv, argc
- return Operation::create(m_graphPool, Meta::TailCall,
- 6, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getCall(Operation::Kind callee)
-{
- const bool canThrow = CallPayload::canThrow(callee);
- const Type retTy = CallPayload::returnType(callee);
- uint16_t nControlInputs = 0;
- uint16_t nControlOutputs = 0;
- if (canThrow) {
- nControlInputs = 1;
- nControlOutputs += 2;
- }
- if (CallPayload::changesContext(callee)) {
- nControlInputs = 1;
- nControlOutputs = std::max<uint16_t>(nControlInputs, 1);
- }
- if (callee == Meta::Throw || callee == Meta::ThrowReferenceError ||
- callee == Meta::JSIteratorNext || callee == Meta::JSIteratorNextForYieldStar) {
- nControlInputs = 1;
- nControlOutputs = 1;
- }
- Operation::Flags flags = Operation::NoFlags;
- if (canThrow)
- flags = Operation::Flags(flags | Operation::CanThrow);
- if (CallPayload::isPure(callee))
- flags = Operation::Flags(flags | Operation::Pure);
- const uint16_t nEffects = (flags & Operation::Pure) ? 0 : 1;
- const uint16_t nValueOutputs = retTy.isNone() ? 0 : 1;
- const uint16_t nValueInputs = CallPayload::argc(callee);
-
- return OperationWithPayload<CallPayload>::create(
- m_graphPool, Meta::Call,
- nValueInputs, nEffects, nControlInputs,
- nValueOutputs, nEffects, nControlOutputs,
- retTy, flags,
- CallPayload(callee));
-}
-
-Operation *OperationBuilder::getVASeal(uint16_t nElements)
-{
- return Operation::create(m_graphPool, Meta::VASeal,
- nElements + 1, 1, 0, 1, 1, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-QString Operation::debugString() const
-{
- switch (kind()) {
-
- case Meta::Constant:
- return QStringLiteral("Constant[%1]").arg(ConstantPayload::get(*this)->debugString());
- case Meta::Parameter:
- return QStringLiteral("Parameter[%1]").arg(ParameterPayload::get(*this)->debugString());
- case Meta::Call:
- return QStringLiteral("Call[%1]").arg(CallPayload::get(*this)->debugString());
- case Meta::UnwindDispatch:
- return QStringLiteral("UnwindDispatch[%1]").arg(UnwindDispatchPayload::get(*this)
- ->debugString());
- case Meta::HandleUnwind:
- return QStringLiteral("HandleUnwind[%1]").arg(HandleUnwindPayload::get(*this)
- ->debugString());
-
- default:
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(kind()));
- }
-}
-
-QString ConstantPayload::debugString() const
-{
- return debugString(m_value);
-}
-
-QString ConstantPayload::debugString(QV4::Value v)
-{
- if (v.isManaged())
- return QString::asprintf("Ptr: %p", v.heapObject());
- if (v.isEmpty())
- return QStringLiteral("empty");
- return v.toQStringNoThrow();
-}
-
-QString ParameterPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_index);
-}
-
-QString UnwindDispatchPayload::debugString() const
-{
- return QStringLiteral("%1, %2").arg(QString::number(m_fallthroughSuccessor),
- QString::number(m_unwindHandlerOffset));
-}
-
-QString HandleUnwindPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_unwindHandlerOffset);
-}
-
-static Type translateType(RuntimeSupport::ArgumentType t)
-{
- switch (t) {
- case RuntimeSupport::ArgumentType::Int: return Type::int32Type();
- case RuntimeSupport::ArgumentType::Bool: return Type::booleanType();
- case RuntimeSupport::ArgumentType::Void: return Type();
- case RuntimeSupport::ArgumentType::Engine: return Type::rawPointerType();
- case RuntimeSupport::ArgumentType::ValueRef: return Type::anyType();
- case RuntimeSupport::ArgumentType::ValueArray: return Type::anyType();
- case RuntimeSupport::ArgumentType::ReturnedValue: return Type::anyType();
- default: Q_UNREACHABLE();
- }
-}
-
-template<template<typename Operation> class M /* MetaOperation */, typename ReturnValue>
-static ReturnValue operateOnRuntimeCall(Operation::Kind kind, bool abortOnMissingCall = true)
-{
- using K = Operation::Kind;
- using R = Runtime;
-
- switch (kind) {
- case K::Throw: return M<R::ThrowException>::doIt();
- case K::ThrowReferenceError: return M<R::ThrowReferenceError>::doIt();
-
- case K::JSEqual: return M<R::CompareEqual>::doIt();
- case K::JSGreaterThan: return M<R::CompareGreaterThan>::doIt();
- case K::JSGreaterEqual: return M<R::CompareGreaterEqual>::doIt();
- case K::JSLessThan: return M<R::CompareLessThan>::doIt();
- case K::JSLessEqual: return M<R::CompareLessEqual>::doIt();
- case K::JSStrictEqual: return M<R::CompareStrictEqual>::doIt();
-
- case K::JSBitAnd: return M<R::BitAnd>::doIt();
- case K::JSBitOr: return M<R::BitOr>::doIt();
- case K::JSBitXor: return M<R::BitXor>::doIt();
- case K::JSUnsignedShiftRight: return M<R::UShr>::doIt();
- case K::JSShiftRight: return M<R::Shr>::doIt();
- case K::JSShiftLeft: return M<R::Shl>::doIt();
-
- case K::JSAdd: return M<R::Add>::doIt();
- case K::JSSubtract: return M<R::Sub>::doIt();
- case K::JSMultiply: return M<R::Mul>::doIt();
- case K::JSDivide: return M<R::Div>::doIt();
- case K::JSModulo: return M<R::Mod>::doIt();
- case K::JSExponentiate: return M<R::Exp>::doIt();
-
- case K::ToBoolean: return M<R::ToBoolean>::doIt();
- case K::ToObject: return M<R::ToObject>::doIt();
-
- case K::JSNegate: return M<R::UMinus>::doIt();
- case K::JSToNumber: return M<R::ToNumber>::doIt();
-
- case K::JSLoadName: return M<R::LoadName>::doIt();
- case K::JSLoadElement: return M<R::LoadElement>::doIt();
- case K::JSStoreElement: return M<R::StoreElement>::doIt();
- case K::JSGetLookup: return M<R::GetLookup>::doIt();
- case K::JSSetLookupStrict: return M<R::SetLookupStrict>::doIt();
- case K::JSSetLookupSloppy: return M<R::SetLookupSloppy>::doIt();
- case K::JSLoadProperty: return M<R::LoadProperty>::doIt();
- case K::JSStoreProperty: return M<R::StoreProperty>::doIt();
- case K::JSLoadGlobalLookup: return M<R::LoadGlobalLookup>::doIt();
- case K::JSStoreNameSloppy: return M<R::StoreNameSloppy>::doIt();
- case K::JSStoreNameStrict: return M<R::StoreNameStrict>::doIt();
- case K::JSLoadSuperProperty: return M<R::LoadSuperProperty>::doIt();
- case K::JSStoreSuperProperty: return M<R::StoreSuperProperty>::doIt();
- case K::JSLoadClosure: return M<R::Closure>::doIt();
- case K::JSGetIterator: return M<R::GetIterator>::doIt();
- case K::JSIteratorNext: return M<R::IteratorNext>::doIt();
- case K::JSIteratorNextForYieldStar: return M<R::IteratorNextForYieldStar>::doIt();
- case K::JSIteratorClose: return M<R::IteratorClose>::doIt();
- case K::JSDeleteProperty: return M<R::DeleteProperty>::doIt();
- case K::JSDeleteName: return M<R::DeleteName>::doIt();
- case K::JSIn: return M<R::In>::doIt();
- case K::JSInstanceOf: return M<R::Instanceof>::doIt();
- case K::QMLLoadQmlContextPropertyLookup: return M<R::LoadQmlContextPropertyLookup>::doIt();
-
- case K::JSTypeofName: return M<R::TypeofName>::doIt();
- case K::JSTypeofValue: return M<R::TypeofValue>::doIt();
- case K::JSDeclareVar: return M<R::DeclareVar>::doIt();
- case K::JSDestructureRestElement: return M<R::DestructureRestElement>::doIt();
- case K::JSThisToObject: return M<R::ConvertThisToObject>::doIt();
- case K::JSCreateMappedArgumentsObject: return M<R::CreateMappedArgumentsObject>::doIt();
- case K::JSCreateUnmappedArgumentsObject: return M<R::CreateUnmappedArgumentsObject>::doIt();
- case K::JSCreateRestParameter: return M<R::CreateRestParameter>::doIt();
- case K::JSLoadSuperConstructor: return M<R::LoadSuperConstructor>::doIt();
- case K::JSThrowOnNullOrUndefined: return M<R::ThrowOnNullOrUndefined>::doIt();
-
- case K::JSCreateCallContext: return M<R::PushCallContext>::doIt();
- case K::JSCreateCatchContext: return M<R::PushCatchContext>::doIt();
- case K::JSCreateWithContext: return M<R::PushWithContext>::doIt();
- case K::JSCreateBlockContext: return M<R::PushBlockContext>::doIt();
- case K::JSCloneBlockContext: return M<R::CloneBlockContext>::doIt();
- case K::JSCreateScriptContext: return M<R::PushScriptContext>::doIt();
- case K::JSPopScriptContext: return M<R::PopScriptContext>::doIt();
-
- case K::LoadRegExp: return M<R::RegexpLiteral>::doIt();
- case K::JSGetTemplateObject: return M<R::GetTemplateObject>::doIt();
-
- case K::JSCallName: return M<R::CallName>::doIt();
- case K::JSCallValue: return M<R::CallValue>::doIt();
- case K::JSCallElement: return M<R::CallElement>::doIt();
- case K::JSCallLookup: return M<R::CallPropertyLookup>::doIt();
- case K::JSCallProperty: return M<R::CallProperty>::doIt();
- case K::JSCallGlobalLookup: return M<R::CallGlobalLookup>::doIt();
- case K::JSCallPossiblyDirectEval: return M<R::CallPossiblyDirectEval>::doIt();
- case K::JSCallWithReceiver: return M<R::CallWithReceiver>::doIt();
- case K::JSDefineObjectLiteral: return M<R::ObjectLiteral>::doIt();
- case K::JSDefineArray: return M<R::ArrayLiteral>::doIt();
- case K::JSCallWithSpread: return M<R::CallWithSpread>::doIt();
- case K::JSConstruct: return M<R::Construct>::doIt();
- case K::JSConstructWithSpread: return M<R::ConstructWithSpread>::doIt();
- case K::JSTailCall: return M<R::TailCall>::doIt();
- case K::JSCreateClass: return M<R::CreateClass>::doIt();
- default:
- if (abortOnMissingCall)
- Q_UNREACHABLE();
- else
- return ReturnValue();
- }
-}
-
-template<typename Method>
-struct IsRuntimeMethodOperation
-{
- static constexpr bool doIt() { return true; }
-};
-
-bool CallPayload::isRuntimeCall(Operation::Kind m)
-{
- return operateOnRuntimeCall<IsRuntimeMethodOperation, bool>(m, false);
-}
-
-QString CallPayload::debugString() const
-{
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(m_callee));
-}
-
-template<typename Method>
-struct MethodArgcOperation
-{
- static constexpr unsigned doIt() { return RuntimeSupport::argumentCount<Method>(); }
-};
-
-unsigned CallPayload::argc(Operation::Kind callee)
-{
- return operateOnRuntimeCall<MethodArgcOperation, unsigned>(callee);
-}
-
-template<typename Method> struct MethodArg1TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg1Type<Method>(); } };
-template<typename Method> struct MethodArg2TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg2Type<Method>(); } };
-template<typename Method> struct MethodArg3TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg3Type<Method>(); } };
-template<typename Method> struct MethodArg4TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg4Type<Method>(); } };
-template<typename Method> struct MethodArg5TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg5Type<Method>(); } };
-template<typename Method> struct MethodArg6TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg6Type<Method>(); } };
-
-static RuntimeSupport::ArgumentType untranslatedArgumentType(Operation::Kind m, unsigned arg)
-{
- if (m == Meta::JSTailCall) {
- if (arg < 4)
- return RuntimeSupport::ArgumentType::ValueRef;
- else
- return RuntimeSupport::ArgumentType::Invalid;
- }
-
- switch (arg) {
- case 0: return operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m);
- case 1: return operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m);
- case 2: return operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m);
- case 3: return operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m);
- case 4: return operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m);
- case 5: return operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m);
- default: return RuntimeSupport::ArgumentType::Invalid;
- }
-}
-
-bool CallPayload::needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType)
-{
- auto argTy = untranslatedArgumentType(m, arg);
- if (argTy == RuntimeSupport::ArgumentType::ValueArray)
- return true;
- if (argTy != RuntimeSupport::ArgumentType::ValueRef)
- return false;
-
- if (op->kind() == Meta::Constant)
- return true;
-
- return !nodeType.isObject() && !nodeType.isRawPointer() && !nodeType.isAny();
-}
-
-template<typename Method>
-struct MethodRetTyOperation
-{
- static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::retType<Method>(); }
-};
-
-Type CallPayload::returnType(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return Type();
-
- auto t = operateOnRuntimeCall<MethodRetTyOperation, RuntimeSupport::ArgumentType>(m);
- return translateType(t);
-}
-
-static int firstArgumentPositionForType(Operation::Kind m, RuntimeSupport::ArgumentType type)
-{
- if (operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 1;
- if (operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 2;
- if (operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 3;
- if (operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 4;
- if (operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 5;
- if (operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 6;
- return -1;
-}
-
-unsigned CallPayload::varArgsStart(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return 4 - 1;
-
- int pos = firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) - 1;
- Q_ASSERT(pos >= 0);
- return pos;
-}
-
-bool CallPayload::isVarArgsCall(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return true;
- if (lastArgumentIsOutputValue(m))
- return false;
- return firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) != -1;
-}
-
-bool CallPayload::isVarArgsCall() const
-{
- return isVarArgsCall(m_callee);
-}
-
-template<typename Method>
-struct MethodsLastArgumentIsOutputValue
-{
- static constexpr bool doIt() { return Method::lastArgumentIsOutputValue; }
-};
-
-bool CallPayload::lastArgumentIsOutputValue(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodsLastArgumentIsOutputValue, bool>(m);
-}
-
-template<typename Method>
-struct MethodChangesContext
-{
- static constexpr bool doIt() { return Method::changesContext; }
-};
-
-bool CallPayload::changesContext(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodChangesContext, bool>(m);
-}
-
-template<typename Method>
-struct MethodIsPure
-{
- static constexpr bool doIt() { return Method::pure; }
-};
-
-bool CallPayload::isPure(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodIsPure, bool>(m);
-}
-
-template<typename Method>
-struct MethodCanThrow
-{
- static constexpr bool doIt() { return Method::throws; }
-};
-
-bool CallPayload::canThrow(Operation::Kind m)
-{
- switch (m) {
- case Meta::Throw: Q_FALLTHROUGH();
- case Meta::ThrowReferenceError:
- // the execution path following these instructions is already linked up to the exception handler
- return false;
- case Meta::JSIteratorNext: Q_FALLTHROUGH();
- case Meta::JSIteratorNextForYieldStar:
- // special case: see GraphBuilder::generate_IteratorNext
- return false;
- default:
- return operateOnRuntimeCall<MethodCanThrow, bool>(m);
- }
-}
-
-bool CallPayload::takesEngineAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Engine;
-}
-
-bool CallPayload::takesFunctionAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Function;
-}
-
-bool CallPayload::takesFrameAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Frame;
-}
-
-template<typename Method>
-struct GetMethodPtr
-{
- static constexpr void *doIt() { return reinterpret_cast<void *>(&Method::call); }
-};
-
-void *CallPayload::getMethodPtr(Operation::Kind m)
-{
- return operateOnRuntimeCall<GetMethodPtr, void *>(m);
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4operation_p.h b/src/qml/jit/qv4operation_p.h
deleted file mode 100644
index 43214023e8..0000000000
--- a/src/qml/jit/qv4operation_p.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4OPERATION_P_H
-#define QV4OPERATION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qv4ir_p.h>
-#include <private/qqmljsmemorypool_p.h>
-
-#include <QtCore/qatomic.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-namespace Meta {
-enum OpKind: uint16_t {
- FrameState,
- Start,
- End,
-
- Undefined,
- Constant,
- Parameter,
- Empty,
- Engine,
- CppFrame,
- Function,
-
- Jump,
- Return,
- JSTailCall,
- TailCall,
- Branch,
- IfTrue,
- IfFalse,
- Region,
- OnException,
- Phi,
- EffectPhi,
- SelectOutput,
- UnwindDispatch,
- UnwindToLabel,
- HandleUnwind,
- Throw,
- ThrowReferenceError,
-
- Call,
-
- LoadRegExp,
- ScopedLoad,
- ScopedStore,
-
- JSLoadElement,
- JSStoreElement,
- JSGetLookup,
- JSSetLookupStrict,
- JSSetLookupSloppy,
- JSLoadProperty,
- JSStoreProperty,
- JSLoadName,
- JSLoadGlobalLookup,
- JSStoreNameSloppy,
- JSStoreNameStrict,
- JSLoadSuperProperty,
- JSStoreSuperProperty,
- JSLoadClosure,
- JSGetIterator,
- JSIteratorNext,
- JSIteratorNextForYieldStar,
- JSIteratorClose,
- JSDeleteProperty,
- JSDeleteName,
- JSIn,
- JSInstanceOf,
-
- /* ok, these are qml object ops, but we don't care for now and treat them as JS */
- QMLLoadQmlContextPropertyLookup,
- QMLCallQmlContextPropertyLookup,
-
- JSEqual,
- JSGreaterThan,
- JSGreaterEqual,
- JSLessThan,
- JSLessEqual,
- JSStrictEqual,
-
- JSAdd,
- JSSubtract,
- JSMultiply,
- JSDivide,
- JSModulo,
- JSExponentiate,
-
- JSBitAnd,
- JSBitOr,
- JSBitXor,
- JSUnsignedShiftRight,
- JSShiftRight,
- JSShiftLeft,
-
- JSNegate,
- JSToNumber,
-
- JSCallName,
- JSCallValue,
- JSCallElement,
- JSCallProperty,
- JSCallLookup,
- JSCallGlobalLookup,
- JSCallPossiblyDirectEval,
- JSCallWithReceiver,
- JSCallWithSpread,
- JSDefineObjectLiteral,
- JSDefineArray,
- JSCreateClass,
- JSConstruct,
- JSConstructWithSpread,
-
- JSTypeofName,
- JSTypeofValue,
- JSDeclareVar,
- JSDestructureRestElement,
- JSThisToObject,
- JSCreateMappedArgumentsObject,
- JSCreateUnmappedArgumentsObject,
- JSCreateRestParameter,
- JSLoadSuperConstructor,
- JSThrowOnNullOrUndefined,
- JSGetTemplateObject,
- StoreThis,
-
- JSCreateCallContext,
- JSCreateCatchContext,
- JSCreateWithContext,
- JSCreateBlockContext,
- JSCloneBlockContext,
- JSCreateScriptContext,
- JSPopScriptContext,
- PopContext,
-
- GetException,
- SetException,
-
- ToObject,
- ToBoolean,
-
- //### do we need this? Or should a later phase generate JumpIsEmpty?
- IsEmpty,
-
- Alloca,
- VAAlloc,
- VAStore,
- VASeal,
-
- BooleanNot,
- HasException,
-
- // Low level, used by the register allocator and stack allocator:
- Swap,
- Move,
- KindsEnd
-};
-Q_NAMESPACE
-Q_ENUM_NS(OpKind)
-} // namespace Ops
-
-class Operation
-{
- Q_DISABLE_COPY_MOVE(Operation)
-
-public:
- using Kind = Meta::OpKind;
-
- enum Flags: uint8_t {
- NoFlags = 0,
- ThrowsFlag = 1 << 0,
- Pure = 1 << 1, // no read/write side effect, cannot throw, cannot deopt, and is idempotent
- NeedsBytecodeOffsets = 1 << 2,
-
- CanThrow = ThrowsFlag | NeedsBytecodeOffsets,
-
- HasFrameStateInput = 1 << 3,
- };
-
-public:
- static Operation *create(QQmlJS::MemoryPool *pool, Kind kind, uint16_t inValueCount,
- uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount,
- uint16_t outControlCount, Type type, uint8_t flags)
- {
- return pool->New<Operation>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, Flags(flags));
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isConstant() const
- {
- switch (kind()) {
- case Meta::Undefined: Q_FALLTHROUGH();
- case Meta::Constant:
- case Meta::Empty:
- return true;
- default:
- return false;
- }
- }
-
- QString debugString() const;
-
- uint16_t valueInputCount() const { return m_inValueCount; }
- uint16_t effectInputCount() const { return m_inEffectCount; }
- uint16_t controlInputCount() const { return m_inControlCount; }
- uint16_t valueOutputCount() const { return m_outValueCount; }
- uint16_t effectOutputCount() const { return m_outEffectCount; }
- uint16_t controlOutputCount() const { return m_outControlCount; }
-
- unsigned indexOfFirstEffect() const { return m_inValueCount; }
- unsigned indexOfFirstControl() const { return m_inValueCount + m_inEffectCount; }
- unsigned indexOfFrameStateInput() const
- {
- return hasFrameStateInput() ? indexOfFirstControl() + m_inControlCount
- : std::numeric_limits<unsigned>::max();
- }
-
- Type type() const
- { return m_type; }
-
- bool canThrow() const
- { return m_flags & ThrowsFlag; }
-
- bool isPure() const
- { return m_flags & Pure; }
-
- bool needsBytecodeOffsets() const
- { return m_flags & NeedsBytecodeOffsets; }
-
- bool hasFrameStateInput() const
- { return m_flags & HasFrameStateInput; }
-
- unsigned totalInputCount() const
- {
- return valueInputCount() + effectInputCount() + controlInputCount() +
- (hasFrameStateInput() ? 1 : 0);
- }
- unsigned totalOutputCount() const { return valueOutputCount() + effectOutputCount() + controlOutputCount(); }
-
-protected:
- friend class QQmlJS::MemoryPool;
- Operation(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, uint8_t flags)
- : m_kind(kind)
- , m_inValueCount(inValueCount)
- , m_inEffectCount(inEffectCount)
- , m_inControlCount(inControlCount)
- , m_outValueCount(outValueCount)
- , m_outEffectCount(outEffectCount)
- , m_outControlCount(outControlCount)
- , m_type(type)
- , m_flags(Flags(flags))
- {
- }
-
- ~Operation() = default;
-
-private:
- Kind m_kind;
- uint16_t m_inValueCount;
- uint16_t m_inEffectCount;
- uint16_t m_inControlCount;
- uint16_t m_outValueCount;
- uint16_t m_outEffectCount;
- uint16_t m_outControlCount;
- Type m_type;
- Flags m_flags;
-};
-
-template <typename Payload>
-class OperationWithPayload: public Operation
-{
-public:
- static OperationWithPayload *create(QQmlJS::MemoryPool *pool, Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- {
- return pool->New<OperationWithPayload>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags, payload);
- }
-
- const Payload &payload() const
- { return m_payload; }
-
-protected:
- friend class QQmlJS::MemoryPool;
- OperationWithPayload(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- : Operation(kind,
- inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags)
- , m_payload(payload)
- {}
-
- ~OperationWithPayload() = default;
-
-private:
- Payload m_payload;
-};
-
-class ConstantPayload
-{
-public:
- explicit ConstantPayload(QV4::Value v)
- : m_value(v)
- {}
-
- QV4::Value value() const
- { return m_value; }
-
- static const ConstantPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Constant)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ConstantPayload>&>(op).payload();
- }
-
- QString debugString() const;
- static QString debugString(QV4::Value v);
-
-private:
- QV4::Value m_value;
-};
-
-class ParameterPayload
-{
-public:
- ParameterPayload(size_t index, Function::StringId stringId)
- : m_index(index)
- , m_stringId(stringId)
- {}
-
- size_t parameterIndex() const
- { return m_index; }
-
- Function::StringId stringId() const
- { return m_stringId; }
-
- static const ParameterPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Parameter)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ParameterPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- size_t m_index;
- Function::StringId m_stringId;
-};
-
-class CallPayload
-{
-public:
- CallPayload(Operation::Kind callee)
- : m_callee(callee)
- {}
-
- static const CallPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Call)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<CallPayload>&>(op).payload();
- }
-
- static bool isRuntimeCall(Operation::Kind m);
-
- Operation::Kind callee() const { return m_callee; }
- QString debugString() const;
-
- unsigned argc() const { return argc(m_callee); }
- static unsigned argc(Operation::Kind callee);
- static bool needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType);
- static Type returnType(Operation::Kind m);
- static int engineArgumentPosition(Operation::Kind m);
- static int functionArgumentPosition(Operation::Kind m);
-
- static constexpr unsigned NoVarArgs = std::numeric_limits<unsigned>::max();
- static unsigned varArgsStart(Operation::Kind m);
- static bool isVarArgsCall(Operation::Kind m);
- bool isVarArgsCall() const;
- static bool lastArgumentIsOutputValue(Operation::Kind m);
- static bool changesContext(Operation::Kind m);
- static bool isPure(Operation::Kind m);
- static bool canThrow(Operation::Kind m);
- static bool takesEngineAsArg(Operation::Kind m, int arg);
- static bool takesFunctionAsArg(Operation::Kind m, int arg);
- static bool takesFrameAsArg(Operation::Kind m, int arg);
- static void *getMethodPtr(Operation::Kind m);
-
-private:
- Operation::Kind m_callee;
-};
-
-class UnwindDispatchPayload
-{
-public:
- UnwindDispatchPayload(int unwindHandlerOffset, int fallthroughSuccessor)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- , m_fallthroughSuccessor(fallthroughSuccessor)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- int fallthroughSuccessor() const //### unused...
- { return m_fallthroughSuccessor; }
-
- static const UnwindDispatchPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::UnwindDispatch)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<UnwindDispatchPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
- int m_fallthroughSuccessor;
-};
-
-class HandleUnwindPayload
-{
-public:
- HandleUnwindPayload(int unwindHandlerOffset)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- static const HandleUnwindPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::HandleUnwind)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<HandleUnwindPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
-};
-
-class OperationBuilder
-{
- Q_DISABLE_COPY_MOVE(OperationBuilder)
-
- friend class QQmlJS::MemoryPool;
- OperationBuilder(QQmlJS::MemoryPool *graphPool);
-
-public:
- static OperationBuilder *create(QQmlJS::MemoryPool *pool);
- ~OperationBuilder() = delete;
-
- Operation *getConstant(QV4::Value v);
- Operation *getFrameState(uint16_t frameSize);
- Operation *getStart(uint16_t outputCount);
- Operation *getEnd(uint16_t controlInputCount);
- Operation *getParam(unsigned index, Function::StringId name);
- Operation *getRegion(unsigned nControlInputs);
- Operation *getPhi(unsigned nValueInputs);
- Operation *getEffectPhi(unsigned nEffectInputs);
- Operation *getUnwindDispatch(unsigned nControlOutputs, int unwindHandlerOffset, int fallthroughSuccessor);
- Operation *getHandleUnwind(int unwindHandlerOffset);
-
- template<Operation::Kind kind>
- Operation *get() {
- return staticOperation(kind);
- }
-
- Operation *getVASeal(uint16_t nElements);
-
- Operation *getJSVarArgsCall(Operation::Kind kind, uint16_t argc);
- Operation *getJSTailCall(uint16_t argc);
- Operation *getTailCall();
-
- Operation *getCall(Operation::Kind callee);
-
-private:
- QQmlJS::MemoryPool *m_graphPool; // used to store per-graph nodes
- Operation *m_opFrameState = nullptr;
- static Operation *staticOperation(Operation::Kind kind);
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4OPERATION_P_H
diff --git a/src/qml/jit/qv4runtimesupport_p.h b/src/qml/jit/qv4runtimesupport_p.h
deleted file mode 100644
index 0dc6022331..0000000000
--- a/src/qml/jit/qv4runtimesupport_p.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4RUNTIMESUPPORT_P_H
-#define QV4RUNTIMESUPPORT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qv4runtimeapi_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-namespace RuntimeSupport {
-
-template <typename T>
-struct CountArguments {
- static constexpr unsigned count = 0;
-};
-template <typename RetTy, typename... Args>
-struct CountArguments<RetTy (*)(Args... args)> {
- static constexpr unsigned count = sizeof...(Args) ;
-};
-
-template<typename M>
-static constexpr unsigned argumentCount() {
- using type = decltype(&M::call);
- return CountArguments<type>::count;
-}
-
-enum class ArgumentType {
- Invalid,
- Engine,
- Frame,
- Function,
- ValueRef,
- ValueArray,
- ReturnedValue,
- Int,
- Bool,
- Void,
-};
-
-
-template <typename T>
-struct JavaScriptType
-{
- // No default type. We want to make sure everything we do is actually recognized.
-};
-
-template <typename T>
-struct ReturnValue
-{
- // No default type.
-};
-
-template <int I, typename T>
-struct Argument
-{
- // For simplicity, we add a default here. Otherwise we would need to spell out more
- // combinations of I and number of arguments of T.
- static constexpr ArgumentType type = ArgumentType::Invalid;
-};
-
-template <typename RetTy, typename T, typename... Args>
-struct Argument<1, RetTy (*)(T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename T, typename... Args>
-struct Argument<2, RetTy (*)(Arg1, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2, typename T,
- typename... Args>
-struct Argument<3, RetTy (*)(Arg1, Arg2, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename T, typename... Args>
-struct Argument<4, RetTy (*)(Arg1, Arg2, Arg3, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename T, typename... Args>
-struct Argument<5, RetTy (*)(Arg1, Arg2, Arg3, Arg4, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5, typename T, typename... Args>
-struct Argument<6, RetTy (*)(Arg1, Arg2, Arg3, Arg4, Arg5, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename... Args>
-struct ReturnValue<RetTy (*)(Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<RetTy>::type;
-};
-
-template<>
-struct JavaScriptType<QV4::ExecutionEngine *>
-{
- static constexpr ArgumentType type = ArgumentType::Engine;
-};
-
-template<>
-struct JavaScriptType<QV4::CppStackFrame *>
-{
- static constexpr ArgumentType type = ArgumentType::Frame;
-};
-
-template<>
-struct JavaScriptType<QV4::Function *>
-{
- static constexpr ArgumentType type = ArgumentType::Function;
-};
-
-template<>
-struct JavaScriptType<const QV4::Value &>
-{
- static constexpr ArgumentType type = ArgumentType::ValueRef;
-};
-
-template<>
-// We need to pass Value * in order to match a parmeter Value[].
-struct JavaScriptType<QV4::Value *>
-{
- static constexpr ArgumentType type = ArgumentType::ValueArray;
-};
-
-template<>
-struct JavaScriptType<int>
-{
- static constexpr ArgumentType type = ArgumentType::Int;
-};
-
-template<>
-struct JavaScriptType<QV4::Bool>
-{
- static constexpr ArgumentType type = ArgumentType::Bool;
-};
-
-template<>
-struct JavaScriptType<QV4::ReturnedValue>
-{
- static constexpr ArgumentType type = ArgumentType::ReturnedValue;
-};
-
-template<>
-struct JavaScriptType<void>
-{
- static constexpr ArgumentType type = ArgumentType::Void;
-};
-
-template<typename M>
-static constexpr ArgumentType retType() {
- using Type = decltype(&M::call);
- return ReturnValue<Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg1Type() {
- using Type = decltype(&M::call);
- return Argument<1, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg2Type() {
- using Type = decltype(&M::call);
- return Argument<2, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg3Type() {
- using Type = decltype(&M::call);
- return Argument<3, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg4Type() {
- using Type = decltype(&M::call);
- return Argument<4, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg5Type() {
- using Type = decltype(&M::call);
- return Argument<5, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg6Type() {
- using Type = decltype(&M::call);
- return Argument<6, Type>::type;
-}
-
-} // namespace RuntimeSupport
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4RUNTIMESUPPORT_P_H
diff --git a/src/qml/jit/qv4schedulers.cpp b/src/qml/jit/qv4schedulers.cpp
deleted file mode 100644
index 0dffefa951..0000000000
--- a/src/qml/jit/qv4schedulers.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4schedulers_p.h"
-#include "qv4util_p.h"
-#include "qv4graph_p.h"
-#include "qv4blockscheduler_p.h"
-#include "qv4stackframe_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcSched, "qt.v4.ir.scheduling")
-Q_LOGGING_CATEGORY(lcDotCFG, "qt.v4.ir.scheduling.cfg")
-
-static bool needsScheduling(Node *n)
-{
- if (n->operation()->isConstant())
- return false;
- switch (n->opcode()) {
- case Meta::Function: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Phi:
- case Meta::EffectPhi:
- return false;
- default:
- return true;
- }
-}
-
-bool NodeScheduler::canStartBlock(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Start: Q_FALLTHROUGH();
- case Meta::IfTrue:
- case Meta::IfFalse:
- case Meta::Region:
- case Meta::HandleUnwind:
- case Meta::OnException:
- return true;
-
- default:
- return false;
- }
-}
-
-bool NodeScheduler::isControlFlowSplit(Node *node) const
-{
- int nOutputs = node->operation()->controlOutputCount();
- if (nOutputs == 2) {
- // if there is a "missing" control output, it's for exception flow without unwinder
- int controlUses = 0;
- auto uses = node->uses();
- for (auto it = uses.begin(), eit = uses.end(); it != eit; ++it) {
- if (isLive(*it) && it.isUsedAsControl())
- ++controlUses;
- }
- return controlUses == 2;
- }
- return nOutputs > 2;
-}
-
-bool NodeScheduler::isBlockTerminator(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Branch: Q_FALLTHROUGH();
- case Meta::Jump:
- case Meta::Return:
- case Meta::TailCall:
- case Meta::UnwindDispatch:
- case Meta::End:
- return true;
- case Meta::Call:
- return isControlFlowSplit(node);
- default:
- return false;
- }
-}
-
-MIBlock *NodeScheduler::getCommonDominator(MIBlock *one, MIBlock *other) const
-{
- MIBlock::Index a = one->index();
- MIBlock::Index b = other->index();
-
- while (a != b) {
- if (m_dominatorDepthForBlock[a] < m_dominatorDepthForBlock[b])
- b = m_domTree->immediateDominator(b);
- else
- a = m_domTree->immediateDominator(a);
- }
-
- return m_miFunction->block(a);
-}
-
-// For Nodes that end up inside loops, it'd be great if we can move (hoist) them out of the loop.
-// To do that, we need a block that preceeds the loop. (So the block before the loop header.)
-// This function calculates that hoist block if the original block is in a loop.
-MIBlock *NodeScheduler::getHoistBlock(MIBlock *block) const
-{
- if (m_loopInfo->isLoopHeader(block))
- return m_miFunction->block(m_domTree->immediateDominator(block->index()));
-
- // make the loop header a candidate:
- MIBlock *loopHeader = m_loopInfo->loopHeaderFor(block);
- if (loopHeader == nullptr)
- return nullptr; // block is not in a loop
-
- // And now the tricky part: block has to dominate all exits from the loop. If it does not do
- // that, it meanse that there is an exit from the loop that can be reached before block. In
- // that case, hoisting from "block" to "loopHeader" would mean there now is an extra calculation
- // that is not needed for a certain loop exit.
- for (MIBlock *outEdge : m_loopInfo->loopExitsForLoop(loopHeader)) {
- if (getCommonDominator(block, outEdge) != block)
- return nullptr;
- }
-
- return m_miFunction->block(m_domTree->immediateDominator(loopHeader->index()));
-}
-
-NodeScheduler::NodeScheduler(Function *irFunction)
- : m_irFunction(irFunction)
- , m_vregs(irFunction->graph()->nodeCount(), std::numeric_limits<unsigned>::max())
- , m_live(irFunction->graph(), /*collectUses =*/ false /* do explicitly NOT collect uses! */)
-{
-}
-
-MIFunction *NodeScheduler::buildMIFunction()
-{
- m_miFunction = new MIFunction(m_irFunction);
-
- // step 1: build the CFG
- auto roots = buildCFG();
- m_miFunction->renumberBlocks();
- m_miFunction->dump(QStringLiteral("CFG after renumbering"));
-
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->index()
- == MIFunction::StartBlockIndex);
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->instructions().front().opcode()
- == Meta::Start);
-
- // step 2: build the dominator tree
- if (lcDotCFG().isDebugEnabled())
- dumpDotCFG();
- m_domTree.reset(new DominatorTree(m_miFunction));
- m_dominatorDepthForBlock = m_domTree->calculateNodeDepths();
-
- // step 3: find loops
- m_loopInfo.reset(new LoopInfo(*m_domTree.data()));
- m_loopInfo->detectLoops();
-
- // step 4: schedule early
- scheduleEarly(roots);
- showNodesByBlock(QStringLiteral("nodes per block after early scheduling"));
-
- // step 5: schedule late
- scheduleLate(roots);
- showNodesByBlock(QStringLiteral("nodes per block after late scheduling"));
-
- // step 6: schedule instructions in each block
- scheduleNodesInBlock();
-
- m_miFunction->dump(QStringLiteral("MI before block scheduling"));
-
- // step 7: order the basic blocks in the CFG
- BlockScheduler blockScheduler(*m_domTree.data(), *m_loopInfo.data());
- m_miFunction->setBlockOrder(blockScheduler.scheduledBlockSequence());
-
- // we're done
- m_miFunction->renumberInstructions();
- m_miFunction->setVregCount(m_nextVReg);
- m_miFunction->dump(QStringLiteral("MI after scheduling"));
- return m_miFunction;
-}
-
-static Node *splitEdge(Function *irFunction, Node *node, unsigned inputIndex)
-{
- Graph *g = irFunction->graph();
- Node *in = node->input(inputIndex);
- Node *region = g->createNode(g->opBuilder()->getRegion(1), &in, 1);
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &region, 1);
-
- qCDebug(lcSched) << "splitting critical edge from node" << node->id()
- << "to node" << node->input(inputIndex)->id()
- << "by inserting jump node" << jump->id()
- << "and region node" << region->id();
-
- node->replaceInput(inputIndex, jump);
- return jump;
-}
-
-// See Chapter 6.3.1 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-std::vector<Node *> NodeScheduler::buildCFG()
-{
- std::vector<Node *> roots;
- roots.reserve(32);
- NodeWorkList todo(m_irFunction->graph());
-
- auto enqueueControlInputs = [this, &todo](Node *node) {
- for (unsigned i = 0, ei = node->operation()->controlInputCount(); i != ei; ++i) {
- const auto inputIndex = node->operation()->indexOfFirstControl() + i;
- Node *input = node->input(inputIndex);
- Q_ASSERT(input);
- if (node->operation()->kind() == Meta::Region
- && node->operation()->controlInputCount() > 1
- && isControlFlowSplit(input)) {
- // critical edge!
- input = splitEdge(m_irFunction, node, inputIndex);
- m_live.markReachable(input);
- m_live.markReachable(input->controlInput(0));
- }
- if (!isBlockTerminator(input)) {
- auto g = m_irFunction->graph();
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &input, 1);
- node->replaceInput(inputIndex, jump);
- m_live.markReachable(jump);
- qCDebug(lcSched) << "inserting jump node" << jump->id()
- << "between node" << node->id()
- << "and node" << input->id();
- input = jump;
- }
- todo.enqueue(input);
- }
- };
-
- // create the CFG by scheduling control dependencies that start/end blocks:
- todo.enqueue(m_irFunction->graph()->endNode());
- while (Node *node = todo.dequeueNextNodeForVisiting()) {
- Q_ASSERT(isBlockTerminator(node));
-
- if (schedulerData(node)->minimumBlock)
- continue;
-
- MIBlock *b = m_miFunction->addBlock();
-
- qCDebug(lcSched) << "scheduling node" << node->id() << "as terminator for new block"
- << b->index();
- b->instructions().push_front(createMIInstruction(node));
- placeFixed(node, b, Schedule);
- roots.push_back(node);
-
- if (Node *framestate = node->frameStateInput()) {
- placeFixed(framestate, b, DontSchedule);
- qCDebug(lcSched) << ".. also scheduling framestate dependency node" << node->id()
- << "in block" << b->index();
- }
-
- if (node->opcode() == Meta::End) {
- enqueueControlInputs(node);
- continue;
- }
-
- while (true) {
- Node *controlDependency = node->controlInput(0);
- if (!controlDependency)
- break;
- if (todo.isVisited(controlDependency))
- break;
- if (schedulerData(controlDependency)->isFixed)
- break;
-
- if (controlDependency->opcode() == Meta::Start) {
- qCDebug(lcSched) << "placing start node" << controlDependency->id()
- << "in block" << b->index();
- handleStartNode(controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- break; // we're done with this block
- }
- if (isBlockTerminator(controlDependency)) {
- qCDebug(lcSched) << "found terminator node" << controlDependency->id()
- << "for another block, so finish block" << b->index();
- Node *merge = m_irFunction->graph()->createNode(
- m_irFunction->graph()->opBuilder()->getRegion(1), &controlDependency, 1);
- node->replaceInput(node->operation()->indexOfFirstControl(), merge);
- addBlockStart(roots, merge, b);
- placeFixed(merge, b, Schedule);
- m_live.markReachable(merge);
- todo.enqueue(controlDependency);
- break; // we're done with this block
- }
- if (canStartBlock(controlDependency)
- || schedulerData(controlDependency->controlInput())->isFixed) {
- qCDebug(lcSched) << "found block start node" << controlDependency->id()
- << "for this block, so finish block" << b->index();
- addBlockStart(roots, controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- enqueueControlInputs(controlDependency);
- break; // we're done with this block
- }
- qCDebug(lcSched) << "skipping node" << controlDependency->id();
- node = controlDependency;
- }
- }
-
- // link the edges of the MIBlocks, and add basic-block arguments:
- for (MIBlock *toBlock : m_miFunction->blocks()) {
- Q_ASSERT(!toBlock->instructions().empty());
- MIInstr &instr = toBlock->instructions().front();
- Node *toNode = instr.irNode();
- const auto opcode = toNode->operation()->kind();
- if (opcode == Meta::Region) {
- unsigned inputNr = 0;
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- MIInstr &fromTerminator = fromBlock->instructions().back();
- if (fromTerminator.irNode()->opcode() == Meta::Jump ||
- fromTerminator.irNode()->opcode() == Meta::UnwindDispatch) {
- unsigned arg = 0;
- for (const MIOperand &bbArg : toBlock->arguments()) {
- fromTerminator.setOperand(arg++,
- createMIOperand(bbArg.irNode()->input(inputNr)));
- }
- }
- ++inputNr;
- }
- } else if (opcode == Meta::End) {
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- } else if (Node *fromNode = toNode->controlInput()) {
- MIBlock *fromBlock = schedulerData(fromNode)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- }
-
- m_irFunction->dump(QStringLiteral("graph after building CFG"));
-
- auto startBlock = schedulerData(m_irFunction->graph()->startNode())->minimumBlock;
- m_miFunction->setStartBlock(startBlock);
-
- if (lcSched().isDebugEnabled())
- m_miFunction->dump(QStringLiteral("control flow graph before renumbering"));
- m_miFunction->verifyCFG();
-
- return roots;
-}
-
-// See Chapter 6.3.3 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-void NodeScheduler::scheduleEarly(const std::vector<Node *> &roots)
-{
- // scheduling one node might have the effect of queueing its dependencies
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots) {
- todo.enqueue(root);
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleEarly(node, todo);
- }
-}
-
-void NodeScheduler::scheduleEarly(Node *node, NodeWorkList &todo)
-{
- qCDebug(lcSched) << "Scheduling node" << node->id() << "early...";
-
- SchedulerData *sd = schedulerData(node);
-
- if (sd->isFixed) {
- // Fixed nodes already know their schedule early position.
- qCDebug(lcSched) << ".. Fixed node" << node->id() << "is on minimum block"
- << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[sd->minimumBlock->index()];
- }
-
- for (Node *use : node->uses()) {
- if (isLive(use))
- propagateMinimumPosition(sd->minimumBlock, use, todo);
- else
- qCDebug(lcSched) << ".. Skipping node" << use->id() << "as it's not live";
- }
-}
-
-void NodeScheduler::propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode,
- NodeWorkList &todo)
-{
- Q_ASSERT(newMinimumPosition);
-
- SchedulerData *sd = schedulerData(toNode);
- if (sd->isFixed) // nothing to do
- return;
-
- MIBlock::Index minimumBlockIndex = sd->minimumBlock
- ? sd->minimumBlock->index()
- : MIFunction::StartBlockIndex;
- Q_ASSERT(m_domTree->insideSameDominatorChain(newMinimumPosition->index(), minimumBlockIndex));
- if (sd->minimumBlock == nullptr
- || m_dominatorDepthForBlock[newMinimumPosition->index()]
- > m_dominatorDepthForBlock[minimumBlockIndex]) {
- // ok, some input for toNode is scheduled *after* our current minimum depth, so we need
- // to adjust out minimal position. (This might involve rescheduling toNode's uses.)
- place(toNode, newMinimumPosition);
- todo.reEnqueue(toNode);
- qCDebug(lcSched) << ".. Propagating minimum block" << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[newMinimumPosition->index()]
- << "to use node" << toNode->id();
- } else {
- qCDebug(lcSched) << ".. Minimum position" << newMinimumPosition->index()
- << "is not better than" << minimumBlockIndex
- << "for node" << toNode->id();
- }
-}
-
-// See Chapter 6.3.4 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-//
-// There is one extra detail not described in the thesis mentioned above: loop hoisting. Before we
-// place a node in the latest block that dominates all uses, we check if we accidentally sink it
-// *into* a loop (meaning the latest block is inside a loop, where it is not if the earliest
-// possible block would be chosen). If we detect that a nodes is going to sink into a loop, we walk
-// the dominator path from the latest block up to the earliest block, and pick the first block that
-// is in the same loop (if any) as the earlieast block.
-//
-// As noted in the thesis, this strategy might enlongen life times, which could be harmful for
-// values that are simple to re-materialized or re-calculate.
-void NodeScheduler::scheduleLate(const std::vector<Node *> &roots)
-{
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots)
- todo.enqueue(root);
-
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleNodeLate(node, todo);
-}
-
-void NodeScheduler::scheduleNodeLate(Node *node, NodeWorkList &todo)
-{
- if (!needsScheduling(node))
- return;
- qCDebug(lcSched) << "Scheduling node" << node->id() << "late...";
-
- auto sd = schedulerData(node);
- if (sd->unscheduledUses == SchedulerData::NotYetCalculated) {
- sd->unscheduledUses = 0;
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isFixed)
- continue;
- todo.enqueue(use);
- ++sd->unscheduledUses;
- }
- }
-
- if (sd->isFixed) {
- qCDebug(lcSched) << ".. it's fixed";
- enqueueInputs(node, todo);
- return;
- }
-
- if (sd->unscheduledUses) {
- qCDebug(lcSched).noquote() << ".. not all uses are fixed, postpone it."<< todo.status(node);
- return;
- }
-
- MIBlock *&minBlock = sd->minimumBlock;
- if (minBlock == nullptr)
- minBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- MIBlock *commonUseDominator = commonDominatorOfUses(node);
- qCDebug(lcSched) << ".. common use dominator: block" << commonUseDominator->index();
-
- // the minBlock has to dominate the uses, *and* the common dominator of the uses.
- Q_ASSERT(minBlock->index() == commonUseDominator->index() ||
- m_domTree->dominates(minBlock->index(), commonUseDominator->index()));
-
- // we now found the deepest block, so use it as the target block:
- MIBlock *targetBlock = commonUseDominator;
-
- if (node->opcode() == Meta::FrameState) {
- // never hoist framestates: they're used (among other things) to keep their inputs alive, so
- // hoisting them out would end the life-time of those inputs prematurely
- } else {
- // but we want to prevent blocks sinking into loops unnecessary
- MIBlock *hoistBlock = getHoistBlock(targetBlock);
- while (hoistBlock
- && m_dominatorDepthForBlock[hoistBlock->index()]
- >= m_dominatorDepthForBlock[minBlock->index()]) {
- qCDebug(lcSched) << ".. hoisting node" << node->id() << "from block"
- << targetBlock->index() << "to block" << hoistBlock->index();
- // ok, so there a) is a hoist block and b) it's deeper than the minimum block,
- // so lift it up one level ...
- targetBlock = hoistBlock;
- // ... and see if we can lift it one more level
- hoistBlock = getHoistBlock(targetBlock);
- }
- }
-
- qCDebug(lcSched) << ".. fixating it in block" << targetBlock->index()
- << "where the minimum block was" << minBlock->index();
-
- placeFixed(node, targetBlock, DontSchedule);
- enqueueInputs(node, todo);
-}
-
-void NodeScheduler::enqueueInputs(Node *node, NodeWorkList &todo)
-{
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto sd = schedulerData(input);
- if (sd->isFixed)
- continue;
- qCDebug(lcSched).noquote() << "... enqueueing input node" << input->id()
- << todo.status(input);
- if (sd->unscheduledUses != SchedulerData::NotYetCalculated) {
- if (sd->unscheduledUses > 0)
- --sd->unscheduledUses;
- if (sd->unscheduledUses == 0)
- todo.reEnqueue(input);
- } else {
- todo.reEnqueue(input);
- }
- }
-}
-
-Node *NodeScheduler::firstNotFixedUse(Node *node)
-{
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!schedulerData(use)->isFixed)
- return use;
- }
- return nullptr;
-}
-
-MIBlock *NodeScheduler::commonDominatorOfUses(Node *node)
-{
- MIBlock *commonDominator = nullptr;
- for (auto useIt = node->uses().begin(), useEIt = node->uses().end(); useIt != useEIt; ++useIt) {
- Node *use = *useIt;
- if (!isLive(use))
- continue;
- // region nodes use other nodes through their control dependency. But those nodes should
- // already have been placed as block terminators before.
- Q_ASSERT(use->opcode() != Meta::Region);
- if (use->opcode() == Meta::Phi || use->opcode() == Meta::EffectPhi) {
- // find the predecessor block defining this input
- Node *region = use->controlInput(0);
- Node *input = region->controlInput(useIt.inputIndex());
- use = input;
- }
- auto minBlock = schedulerData(use)->minimumBlock;
- if (commonDominator == nullptr)
- commonDominator = minBlock;
- else
- commonDominator = getCommonDominator(commonDominator, minBlock);
- }
- return commonDominator;
-}
-
-void NodeScheduler::scheduleNodesInBlock()
-{
- auto startBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- for (Node *n : m_live.reachable()) {
- auto sd = schedulerData(n);
- if (!sd->minimumBlock)
- sd->minimumBlock = startBlock;
- }
-
- std::vector<std::vector<SchedulerData *>> nodesForBlock;
- nodesForBlock.resize(m_miFunction->blockCount());
-
- for (auto sd : m_schedulerData) {
- if (sd == nullptr)
- continue;
- if (!isLive(sd->node))
- continue;
- sd->unscheduledUses = 0;
- for (Node *use : sd->node->uses()) {
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isScheduledInBlock)
- continue;
- if (schedulerData(use)->minimumBlock == sd->minimumBlock)
- ++sd->unscheduledUses;
- }
- if (sd->unscheduledUses == 0)
- nodesForBlock[sd->minimumBlock->index()].push_back(sd);
- }
-
- NodeWorkList todo(m_irFunction->graph());
- for (MIBlock *b : m_miFunction->blocks()) {
- qCDebug(lcSched) << "Scheduling inside block" << b->index();
- MIInstr *insertionPoint = &b->instructions().back();
- todo.enqueue(insertionPoint->irNode());
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- for (auto sd : nodesForBlock[b->index()]) {
- if (!sd->isScheduledInBlock)
- todo.enqueue(sd->node);
- }
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- todo.reset();
- }
-}
-
-void NodeScheduler::scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo)
-{
- while (Node *n = todo.dequeueNextNodeForVisiting())
- scheduleNodeInBlock(n, insertionPoint, b, todo);
-}
-
-void NodeScheduler::scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b,
- NodeWorkList &todo)
-{
- Q_ASSERT(!node->isDead());
-
- if (!isLive(node))
- return;
-
- if (!needsScheduling(node))
- return;
-
- auto nodeData = schedulerData(node);
- if (nodeData->minimumBlock != b)
- return;
-
- const bool wasAlreadyScheduled = nodeData->isScheduledInBlock;
- if (!wasAlreadyScheduled) {
- if (nodeData->unscheduledUses)
- return;
-
- scheduleNodeNow(node, insertionPoint);
- }
-
- if (Node *framestate = node->frameStateInput())
- scheduleNodeInBlock(framestate, insertionPoint, b, todo);
-
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto inputInfo = schedulerData(input);
- if (inputInfo->isScheduledInBlock)
- continue;
- Q_ASSERT(inputInfo->minimumBlock != nullptr);
- if (inputInfo->minimumBlock != b)
- continue;
- Q_ASSERT(!input->isDead());
- Q_ASSERT(inputInfo->unscheduledUses != SchedulerData::NotYetCalculated);
- if (!wasAlreadyScheduled && inputInfo->unscheduledUses > 0)
- --inputInfo->unscheduledUses;
- if (inputInfo->unscheduledUses == 0)
- todo.enqueue(input);
- }
-}
-
-void NodeScheduler::scheduleNodeNow(Node *node, MIInstr *&insertionPoint)
-{
- qCDebug(lcSched) << ".. scheduling node" << node->id()
- << "in block" << insertionPoint->parent()->index()
- << "before node" << insertionPoint->irNode()->id();
-
- MIInstr *newInstr = createMIInstruction(node);
- newInstr->insertBefore(insertionPoint);
- insertionPoint = newInstr;
-}
-
-void NodeScheduler::place(Node *node, MIBlock *b)
-{
- Q_ASSERT(!node->isDead());
-
- if (b == nullptr)
- return;
-
- schedulerData(node)->minimumBlock = b;
-}
-
-void NodeScheduler::placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled)
-{
- place(node, b);
- auto sd = schedulerData(node);
- Q_ASSERT(!sd->isFixed);
- sd->isFixed = true;
- sd->isScheduledInBlock = markScheduled == Schedule;
-}
-
-unsigned NodeScheduler::vregForNode(Node *node)
-{
- unsigned &vreg = m_vregs[unsigned(node->id())];
- if (vreg == std::numeric_limits<unsigned>::max())
- vreg = m_nextVReg++;
- return vreg;
-}
-
-void NodeScheduler::addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block)
-{
- block->instructions().insert(block->instructions().begin(), createMIInstruction(startNode));
- if (startNode->opcode() == Meta::Region) {
- for (Node *use : startNode->uses()) {
- if (use->opcode() == Meta::Phi && isLive(use)) {
- block->addArgument(MIOperand::createVirtualRegister(use, vregForNode(use)));
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- } else if (use->opcode() == Meta::EffectPhi && isLive(use)) {
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- }
- }
- }
-}
-
-void NodeScheduler::handleStartNode(Node *startNode, MIBlock *startBlock)
-{
- startBlock->instructions().push_front(createMIInstruction(startNode));
-
- QVarLengthArray<Node *, 32> args;
- for (Node *use : startNode->uses()) {
- switch (use->opcode()) {
- case Meta::Engine: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Function:
- placeFixed(use, startBlock, Schedule);
- break;
- case Meta::Parameter: {
- auto param = ParameterPayload::get(*use->operation());
- int idx = int(param->parameterIndex());
- if (args.size() <= idx)
- args.resize(idx + 1);
- args[int(idx)] = use;
- placeFixed(use, startBlock, Schedule);
- }
- break;
- default:
- break;
- }
- }
-
- for (unsigned i = 0, ei = unsigned(args.size()); i != ei; ++i) {
- if (Node *arg = args.at(int(i)))
- startBlock->addArgument(MIOperand::createJSStackSlot(arg, i));
- }
-}
-
-static Node *firstControlOutput(Node *n)
-{
- for (auto it = n->uses().begin(), eit = n->uses().end(); it != eit; ++it) {
- if (it.isUsedAsControl())
- return *it;
- }
- return nullptr;
-}
-
-MIInstr *NodeScheduler::createMIInstruction(Node *node)
-{
- const auto opcode = node->operation()->kind();
-
- unsigned nArgs = 0;
- switch (opcode) {
- case Meta::UnwindDispatch: Q_FALLTHROUGH();
- case Meta::Jump: {
- Node *target = firstControlOutput(node);
- if (target->opcode() == Meta::Region) {
- for (Node *n : target->uses()) {
- if (n->opcode() == Meta::Phi && isLive(n))
- ++nArgs;
- }
- }
- }
- break;
- case Meta::Branch:
- nArgs = 1;
- break;
- case Meta::Return:
- nArgs = 1;
- break;
- default:
- nArgs = node->operation()->valueInputCount();
- break;
- }
-
- MIInstr *instr = MIInstr::create(m_irFunction->pool(), node, nArgs);
- for (unsigned i = 0, ei = node->operation()->valueInputCount(); i != ei; ++i)
- instr->setOperand(i, createMIOperand(node->input(i)));
- if (node->opcode() != Meta::Start && node->operation()->valueOutputCount() > 0)
- instr->setDestination(createMIOperand(node));
-
- schedulerData(node)->isScheduledInBlock = true;
- return instr;
-}
-
-MIOperand NodeScheduler::createMIOperand(Node *node)
-{
- if (node->operation()->isConstant())
- return MIOperand::createConstant(node);
-
- auto opcode = node->operation()->kind();
- switch (opcode) {
- case Meta::Parameter:
- return MIOperand::createJSStackSlot(
- node, unsigned(ParameterPayload::get(*node->operation())->parameterIndex()));
- case Meta::Engine:
- return MIOperand::createEngineRegister(node);
- case Meta::CppFrame:
- return MIOperand::createCppFrameRegister(node);
- case Meta::Function:
- return MIOperand::createFunction(node);
- default:
- if ((node->opcode() == Meta::Call
- && CallPayload::get(*node->operation())->callee() == Meta::JSThisToObject)
- || node->opcode() == Meta::StoreThis) {
- return MIOperand::createJSStackSlot(node, CallData::This);
- } else {
- return MIOperand::createVirtualRegister(node, vregForNode(node));
- }
- }
-}
-
-void NodeScheduler::showNodesByBlock(const QString &description) const
-{
- if (!lcSched().isDebugEnabled())
- return;
-
- qCDebug(lcSched) << description;
-
- for (MIBlock *b : m_miFunction->blocks()) {
- QString s;
- for (const SchedulerData *sd : m_schedulerData) {
- if (!sd)
- continue;
- if (!isLive(sd->node))
- continue;
- if (sd->minimumBlock == b) {
- if (!s.isEmpty())
- s += QStringLiteral(", ");
- s += QStringLiteral("%1 (%2)").arg(QString::number(sd->node->id()),
- sd->node->operation()->debugString());
- }
- }
- if (s.isEmpty())
- s = QStringLiteral("<<none>>");
- qCDebug(lcSched, "Nodes in block %u: %s", b->index(), s.toUtf8().constData());
- }
-}
-
-void NodeScheduler::dumpDotCFG() const
-{
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"L%1\" label=\"Control Flow Graph\";"
- "node[shape=circle];edge[dir=forward fontsize=10]\n")
- .arg(MIFunction::StartBlockIndex);
- for (MIBlock *src : m_miFunction->blocks()) {
- for (MIBlock *dst : src->outEdges()) {
- out += QStringLiteral("L%1->L%2\n").arg(QString::number(src->index()),
- QString::number(dst->index()));
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotCFG).nospace().noquote() << out;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4schedulers_p.h b/src/qml/jit/qv4schedulers_p.h
deleted file mode 100644
index f9179816df..0000000000
--- a/src/qml/jit/qv4schedulers_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4SCHEDULER_P_H
-#define QV4SCHEDULER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qv4global_p.h"
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Node scheduling "flattens" the graph into basic blocks with an ordered list of instructions.
-//
-// The various steps are mentioned in buildMIFunction, but the general idea is described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf in chapter 6.
-class NodeScheduler final
-{
- Q_DISABLE_COPY_MOVE(NodeScheduler)
-
- class SchedulerData final {
- Q_DISABLE_COPY_MOVE(SchedulerData)
- public:
- static SchedulerData *create(QQmlJS::MemoryPool *pool)
- { return pool->New<SchedulerData>(); }
-
- SchedulerData() = default;
- ~SchedulerData() = default;
-
- Node *node = nullptr;
- MIBlock *minimumBlock = nullptr;
- bool isFixed = false;
- bool isScheduledInBlock = false;
- static constexpr unsigned NotYetCalculated = std::numeric_limits<unsigned>::max();
- unsigned unscheduledUses = NotYetCalculated;
- };
-
-public:
- NodeScheduler(Function *irFunction);
- ~NodeScheduler() = default;
-
- MIFunction *buildMIFunction();
-
-private:
- std::vector<Node *> buildCFG();
- void scheduleEarly(const std::vector<Node *> &roots);
- void scheduleEarly(Node *node, NodeWorkList &todo);
- void propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode, NodeWorkList &todo);
- void scheduleLate(const std::vector<Node *> &roots);
- void scheduleNodeLate(Node *node, NodeWorkList &todo);
- void enqueueInputs(Node *node, NodeWorkList &todo);
- Node *firstNotFixedUse(Node *node);
- MIBlock *commonDominatorOfUses(Node *node);
- void scheduleNodesInBlock();
- void scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeNow(Node *node, MIInstr *&insertionPoint);
-
- void place(Node *node, MIBlock *b);
- enum ScheduleOrNot { DontSchedule, Schedule };
- void placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled);
- unsigned vregForNode(Node *node);
- void addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block);
- void enqueueControlInputs(Node *node);
- void handleStartNode(Node *startNode, MIBlock *startBlock);
- MIInstr *createMIInstruction(Node *node);
- MIOperand createMIOperand(Node *node);
- SchedulerData *schedulerData(Node *n)
- {
- if (Q_UNLIKELY(m_schedulerData.size() <= n->id()))
- m_schedulerData.resize(n->id() + 8);
- SchedulerData *&sd = m_schedulerData[n->id()];
- if (Q_UNLIKELY(sd == nullptr)) {
- sd = SchedulerData::create(m_irFunction->pool());
- sd->node = n;
- }
- return sd;
- }
- bool isLive(Node *n) const
- { return m_live.isReachable(n->id()); }
- bool canStartBlock(Node *node) const;
- bool isControlFlowSplit(Node *node) const;
- bool isBlockTerminator(Node *node) const;
- MIBlock *getCommonDominator(MIBlock *one, MIBlock *other) const;
- MIBlock *getHoistBlock(MIBlock *block) const;
-
- void showNodesByBlock(const QString &description) const;
-
- void dumpDotCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- MIFunction *m_miFunction = nullptr;
- QScopedPointer<LoopInfo> m_loopInfo;
- QScopedPointer<DominatorTree> m_domTree;
- std::vector<int> m_dominatorDepthForBlock;
- std::vector<unsigned> m_vregs;
- std::vector<SchedulerData *> m_schedulerData;
- NodeCollector m_live;
- unsigned m_nextVReg = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4SCHEDULER_P_H
diff --git a/src/qml/jit/qv4tracingjit.cpp b/src/qml/jit/qv4tracingjit.cpp
deleted file mode 100644
index c8974b3a1b..0000000000
--- a/src/qml/jit/qv4tracingjit.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4vme_moth_p.h"
-#include "qv4graphbuilder_p.h"
-#include "qv4lowering_p.h"
-#include "qv4mi_p.h"
-#include "qv4schedulers_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTracing, "qt.v4.tracing")
-
-namespace QV4 {
-
-// This is the entry point for the "tracing JIT". It uses the sea-of-nodes concept as described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf
-//
-// The minimal pipeline is as follows:
-// - create the graph for the function
-// - do generic lowering
-// - schedule the nodes
-// - run minimal stack slot allocation (no re-use of slots)
-// - run the assembler
-//
-// This pipeline has no optimizations, and generates quite inefficient code. It does have the
-// advantage that no trace information is used, so it can be used for testing where it replaces
-// the baseline JIT. Any optimizations are additions to this pipeline.
-//
-// Note: generators (or resuming functions in general) are not supported by this JIT.
-void Moth::runTracingJit(QV4::Function *function)
-{
- IR::Function irFunction(function);
- qCDebug(lcTracing).noquote() << "runTracingJit called for" << irFunction.name() << "...";
-
- qCDebug(lcTracing).noquote().nospace() << function->traceInfoToString();
-
- IR::GraphBuilder::buildGraph(&irFunction);
- irFunction.dump(QStringLiteral("initial IR"));
- irFunction.verify();
-
- IR::GenericLowering(irFunction).lower();
- irFunction.dump(QStringLiteral("after generic lowering"));
- irFunction.verify();
-
- IR::NodeScheduler scheduler(&irFunction);
- QScopedPointer<IR::MIFunction> miFunction(scheduler.buildMIFunction());
- miFunction->dump(QStringLiteral("initial MI"));
- irFunction.verify();
-}
-
-} // QV4 namespace
-QT_END_NAMESPACE