aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/compiler.pri4
-rw-r--r--src/qml/compiler/qv4codegen.cpp14
-rw-r--r--src/qml/compiler/qv4codegen_p.h1
-rw-r--r--src/qml/compiler/qv4compileddata.cpp157
-rw-r--r--src/qml/compiler/qv4compileddata_p.h354
-rw-r--r--src/qml/compiler/qv4compiler.cpp313
-rw-r--r--src/qml/compiler/qv4compiler_p.h99
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h62
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp247
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h62
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp139
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h27
-rw-r--r--src/qml/compiler/qv4isel_p.cpp50
-rw-r--r--src/qml/compiler/qv4isel_p.h21
-rw-r--r--src/qml/compiler/qv4jsir.cpp9
-rw-r--r--src/qml/compiler/qv4jsir_p.h5
-rw-r--r--src/qml/jsruntime/qv4context.cpp26
-rw-r--r--src/qml/jsruntime/qv4context_p.h12
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp22
-rw-r--r--src/qml/jsruntime/qv4engine.cpp46
-rw-r--r--src/qml/jsruntime/qv4engine_p.h8
-rw-r--r--src/qml/jsruntime/qv4function.cpp82
-rw-r--r--src/qml/jsruntime/qv4function_p.h61
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp15
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp17
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp40
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h14
-rw-r--r--src/qml/jsruntime/qv4script.cpp37
-rw-r--r--src/qml/jsruntime/qv4unwindhelper_p-arm.h4
-rw-r--r--src/qml/jsruntime/qv4unwindhelper_p-dw2.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp57
-rw-r--r--tools/v4/main.cpp2
32 files changed, 1499 insertions, 516 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index a19bf70a7a..51a7270598 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -4,6 +4,8 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
HEADERS += \
+ $$PWD/qv4compileddata_p.h \
+ $$PWD/qv4compiler_p.h \
$$PWD/qv4codegen_p.h \
$$PWD/qv4isel_masm_p.h \
$$PWD/qv4isel_p.h \
@@ -15,6 +17,8 @@ HEADERS += \
$$PWD/qv4regalloc_p.h
SOURCES += \
+ $$PWD/qv4compileddata.cpp \
+ $$PWD/qv4compiler.cpp \
$$PWD/qv4codegen.cpp \
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4isel_masm.cpp \
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b91e3ccd26..6c913a6dc4 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -470,10 +470,11 @@ V4IR::Function *Codegen::operator()(const QString &fileName,
{
assert(node);
- _fileName = fileName;
_module = module;
_env = 0;
+ _module->setFileName(fileName);
+
ScanFunctions scan(this, sourceCode);
scan(node);
@@ -490,8 +491,8 @@ V4IR::Function *Codegen::operator()(const QString &fileName,
AST::FunctionExpression *ast,
V4IR::Module *module)
{
- _fileName = fileName;
_module = module;
+ _module->setFileName(fileName);
_env = 0;
ScanFunctions scan(this, sourceCode);
@@ -1794,7 +1795,6 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
enterEnvironment(ast);
V4IR::Function *function = _module->newFunction(name, _function);
- function->sourceFile = _fileName;
V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock());
V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
@@ -2575,7 +2575,7 @@ void Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr *expr, co
void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
QQmlError error;
- error.setUrl(QUrl::fromLocalFile(_fileName));
+ error.setUrl(QUrl::fromLocalFile(_module->fileName));
error.setDescription(detail);
error.setLine(loc.startLine);
error.setColumn(loc.startColumn);
@@ -2585,7 +2585,7 @@ void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
QQmlError error;
- error.setUrl(QUrl::fromLocalFile(_fileName));
+ error.setUrl(QUrl::fromLocalFile(_module->fileName));
error.setDescription(detail);
error.setLine(loc.startLine);
error.setColumn(loc.startColumn);
@@ -2594,10 +2594,10 @@ void Codegen::throwReferenceError(const SourceLocation &loc, const QString &deta
void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
{
- context->throwSyntaxError(detail, _fileName, loc.startLine, loc.startColumn);
+ context->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
{
- context->throwReferenceError(detail, _fileName, loc.startLine, loc.startColumn);
+ context->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index c55a45b107..85c38d8d8c 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -413,7 +413,6 @@ protected:
QList<QQmlError> errors();
protected:
- QString _fileName;
Result _expr;
QString _property;
UiMember _uiMember;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
new file mode 100644
index 0000000000..a434f6c0dc
--- /dev/null
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4compileddata_p.h"
+#include "qv4jsir_p.h"
+#include <private/qv4engine_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4unwindhelper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace CompiledData {
+
+namespace {
+ bool functionSortHelper(QV4::Function *lhs, QV4::Function *rhs)
+ {
+ return reinterpret_cast<quintptr>(lhs->code) < reinterpret_cast<quintptr>(rhs->code);
+ }
+}
+
+CompilationUnit::~CompilationUnit()
+{
+ engine->compilationUnits.erase(engine->compilationUnits.find(this));
+ free(data);
+ free(runtimeStrings);
+ delete [] runtimeLookups;
+ delete [] runtimeRegularExpressions;
+ free(runtimeClasses);
+ qDeleteAll(runtimeFunctions);
+}
+
+QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
+{
+ this->engine = engine;
+ engine->compilationUnits.insert(this);
+
+ assert(!runtimeStrings);
+ assert(data);
+ runtimeStrings = (QV4::String**)malloc(data->stringTableSize * sizeof(QV4::String*));
+ for (int i = 0; i < data->stringTableSize; ++i)
+ runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
+
+ runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
+ for (int i = 0; i < data->regexpTableSize; ++i) {
+ const CompiledData::RegExp *re = data->regexpAt(i);
+ int flags = 0;
+ if (re->flags & CompiledData::RegExp::RegExp_Global)
+ flags |= QQmlJS::V4IR::RegExp::RegExp_Global;
+ if (re->flags & CompiledData::RegExp::RegExp_IgnoreCase)
+ flags |= QQmlJS::V4IR::RegExp::RegExp_IgnoreCase;
+ if (re->flags & CompiledData::RegExp::RegExp_Multiline)
+ flags |= QQmlJS::V4IR::RegExp::RegExp_Multiline;
+ QV4::RegExpObject *obj = engine->newRegExpObject(data->stringAt(re->stringIndex), flags);
+ runtimeRegularExpressions[i] = QV4::Value::fromObject(obj);
+ }
+
+ if (data->lookupTableSize) {
+ runtimeLookups = new QV4::Lookup[data->lookupTableSize];
+ const CompiledData::Lookup *compiledLookups = data->lookupTable();
+ for (uint i = 0; i < data->lookupTableSize; ++i) {
+ QV4::Lookup *l = runtimeLookups + i;
+
+ if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Getter)
+ l->getter = QV4::Lookup::getterGeneric;
+ else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Setter)
+ l->setter = QV4::Lookup::setterGeneric;
+ else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_GlobalGetter)
+ l->globalGetter = QV4::Lookup::globalGetterGeneric;
+
+ for (int i = 0; i < QV4::Lookup::Size; ++i)
+ l->classList[i] = 0;
+ l->level = -1;
+ l->index = UINT_MAX;
+ l->name = runtimeStrings[compiledLookups[i].nameIndex];
+ }
+ }
+
+ if (data->jsClassTableSize) {
+ runtimeClasses = (QV4::InternalClass**)malloc(data->jsClassTableSize * sizeof(QV4::InternalClass*));
+
+ for (int i = 0; i < data->jsClassTableSize; ++i) {
+ int memberCount = 0;
+ const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
+ QV4::InternalClass *klass = engine->emptyClass;
+ for (int j = 0; j < memberCount; ++j, ++member)
+ klass = klass->addMember(runtimeStrings[member->nameOffset], member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
+
+ runtimeClasses[i] = klass;
+ }
+ }
+
+ linkBackendToEngine(engine);
+
+ runtimeFunctionsSortedByAddress.resize(runtimeFunctions.size());
+ memcpy(runtimeFunctionsSortedByAddress.data(), runtimeFunctions.data(), runtimeFunctions.size() * sizeof(QV4::Function*));
+ qSort(runtimeFunctionsSortedByAddress.begin(), runtimeFunctionsSortedByAddress.end(), functionSortHelper);
+
+ return runtimeFunctions[data->indexOfRootFunction];
+}
+
+void CompilationUnit::markObjects()
+{
+ for (int i = 0; i < data->stringTableSize; ++i)
+ runtimeStrings[i]->mark();
+ for (int i = 0; i < data->regexpTableSize; ++i)
+ runtimeRegularExpressions[i].mark();
+ for (int i = 0; i < runtimeFunctions.count(); ++i)
+ runtimeFunctions[i]->mark();
+}
+
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
new file mode 100644
index 0000000000..854df1185b
--- /dev/null
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4COMPILEDDATA_P_H
+#define QV4COMPILEDDATA_P_H
+
+#include <QtCore/qstring.h>
+#include <QVector>
+#include <QStringList>
+#include <private/qv4value_def_p.h>
+#include <private/qv4executableallocator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace V4IR {
+struct Function;
+}
+}
+
+namespace QV4 {
+
+struct Function;
+struct ExecutionContext;
+
+namespace CompiledData {
+
+struct String;
+struct Function;
+struct Lookup;
+struct RegExp;
+
+struct RegExp
+{
+ enum Flags {
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04
+ };
+ quint32 flags;
+ quint32 stringIndex;
+
+ static int calculateSize() { return sizeof(RegExp); }
+};
+
+struct Lookup
+{
+ enum Type {
+ Type_Getter = 0x0,
+ Type_Setter = 0x1,
+ Type_GlobalGetter = 2
+ };
+
+ quint32 type_and_flags;
+ quint32 nameIndex;
+
+ static int calculateSize() { return sizeof(Lookup); }
+};
+
+struct JSClassMember
+{
+ uint nameOffset : 31;
+ uint isAccessor : 1;
+};
+
+struct JSClass
+{
+ uint nMembers;
+ // JSClassMember[nMembers]
+
+ static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
+};
+
+struct String
+{
+ quint32 hash;
+ quint32 flags; // isArrayIndex
+ QArrayData str;
+ // uint16 strdata[]
+
+ static int calculateSize(const QString &str) {
+ return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
+ }
+};
+
+static const char magic_str[] = "qv4cdata";
+
+struct Unit
+{
+ char magic[8];
+ qint16 architecture;
+ qint16 version;
+
+ enum {
+ IsJavascript = 0x1,
+ IsQml = 0x2,
+ StaticData = 0x4 // Unit data persistent in memory?
+ };
+ quint32 flags;
+ uint stringTableSize;
+ uint offsetToStringTable;
+ uint functionTableSize;
+ uint offsetToFunctionTable;
+ uint lookupTableSize;
+ uint offsetToLookupTable;
+ uint regexpTableSize;
+ uint offsetToRegexpTable;
+ uint jsClassTableSize;
+ uint offsetToJSClassTable;
+ uint indexOfRootFunction;
+ quint32 sourceFileIndex;
+
+ QString stringAt(int idx) const {
+ const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
+ const uint offset = offsetTable[idx];
+ const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
+ QStringDataPtr holder = { const_cast<QStringData *>(static_cast<const QStringData*>(&str->str)) };
+ QString qstr(holder);
+ if (flags & StaticData)
+ return qstr;
+ return QString(qstr.constData(), qstr.length());
+ }
+
+ const Function *functionAt(int idx) const {
+ const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable);
+ const uint offset = offsetTable[idx];
+ return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
+ }
+
+ const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
+ const RegExp *regexpAt(int index) const {
+ return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
+ }
+
+ const JSClassMember *jsClassAt(int idx, int *nMembers) const {
+ const uint *offsetTable = reinterpret_cast<const uint *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
+ const uint offset = offsetTable[idx];
+ const char *ptr = reinterpret_cast<const char *>(this) + offset;
+ const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
+ *nMembers = klass->nMembers;
+ return reinterpret_cast<const JSClassMember*>(ptr + sizeof(JSClass));
+ }
+
+ static int calculateSize(uint nStrings, uint nFunctions, uint nRegExps,
+ uint nLookups, uint nClasses) {
+ return (sizeof(Unit)
+ + (nStrings + nFunctions + nClasses) * sizeof(uint)
+ + nRegExps * RegExp::calculateSize()
+ + nLookups * Lookup::calculateSize()
+ + 7) & ~7; }
+};
+
+struct Function
+{
+ enum Flags {
+ HasDirectEval = 0x1,
+ UsesArgumentsObject = 0x2,
+ IsStrict = 0x4,
+ IsNamedExpression = 0x8
+ };
+
+ quint32 index; // in CompilationUnit's function table
+ quint32 nameIndex;
+ qint64 flags;
+ quint32 nFormals;
+ quint32 formalsOffset;
+ quint32 nLocals;
+ quint32 localsOffset;
+ quint32 nLineNumberMappingEntries;
+ quint32 lineNumberMappingOffset; // Array of uint pairs (offset and line number)
+ quint32 nInnerFunctions;
+ quint32 innerFunctionsOffset;
+// quint32 formalsIndex[nFormals]
+// quint32 localsIndex[nLocals]
+// quint32 offsetForInnerFunctions[nInnerFunctions]
+// Function[nInnerFunctions]
+
+ const quint32 *formalsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
+ const quint32 *localsTable() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
+ const quint32 *lineNumberMapping() const { return reinterpret_cast<const quint32 *>(reinterpret_cast<const char *>(this) + lineNumberMappingOffset); }
+
+ static int calculateSize(int nFormals, int nLocals, int nInnerfunctions, int lineNumberMappings) {
+ return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + 2 * lineNumberMappings) * sizeof(quint32) + 7) & ~0x7;
+ }
+};
+
+// Qml data structures
+
+struct Value
+{
+ quint32 type; // Invalid, Boolean, Number, String, Function, Object, ListOfObjects
+ union {
+ bool b;
+ int i;
+ double d;
+ quint32 offsetToString;
+ quint32 offsetToFunction;
+ quint32 offsetToObject;
+ };
+};
+
+struct Binding
+{
+ quint32 offsetToPropertyName;
+ Value value;
+};
+
+struct Parameter
+{
+ quint32 offsetToName;
+ quint32 type;
+ quint32 offsetToCustomTypeName;
+ quint32 reserved;
+};
+
+struct Signal
+{
+ quint32 offsetToName;
+ quint32 nParameters;
+ Parameter parameters[1];
+};
+
+struct Property
+{
+ quint32 offsetToName;
+ quint32 type;
+ quint32 offsetToCustomTypeName;
+ quint32 flags; // default, readonly
+ Value value;
+};
+
+struct Object
+{
+ quint32 offsetToInheritedTypeName;
+ quint32 offsetToId;
+ quint32 offsetToDefaultProperty;
+ quint32 nFunctions;
+ quint32 offsetToFunctions;
+ quint32 nProperties;
+ quint32 offsetToProperties;
+ quint32 nSignals;
+ quint32 offsetToSignals;
+ quint32 nBindings;
+ quint32 offsetToBindings;
+// Function[]
+// Property[]
+// Signal[]
+// Binding[]
+};
+
+struct Imports
+{
+};
+
+
+struct QmlUnit
+{
+ Unit header;
+ int offsetToTypeName;
+ Imports imports;
+ Object object;
+};
+
+// This is how this hooks into the existing structures:
+
+//VM::Function
+// CompilationUnit * (for functions that need to clean up)
+// CompiledData::Function *compiledFunction
+
+struct CompilationUnit
+{
+ CompilationUnit()
+ : refCount(0)
+ , engine(0)
+ , data(0)
+ , runtimeStrings(0)
+ , runtimeLookups(0)
+ , runtimeClasses(0)
+ {}
+ virtual ~CompilationUnit();
+
+ void ref() { ++refCount; }
+ void deref() { if (!--refCount) delete this; }
+
+ int refCount;
+ ExecutionEngine *engine;
+ Unit *data;
+
+ QString fileName() const { return data->stringAt(data->sourceFileIndex); }
+
+ QV4::String **runtimeStrings; // Array
+ QV4::Lookup *runtimeLookups;
+ QV4::Value *runtimeRegularExpressions;
+ QV4::InternalClass **runtimeClasses;
+ QVector<QV4::Function *> runtimeFunctions;
+ QVector<QV4::Function *> runtimeFunctionsSortedByAddress;
+
+ QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
+
+ virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; }
+
+ // ### runtime data
+ // pointer to qml data for QML unit
+
+ void markObjects();
+
+protected:
+ virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
+};
+
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
new file mode 100644
index 0000000000..322a39932a
--- /dev/null
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qv4compiler_p.h>
+#include <qv4compileddata_p.h>
+#include <qv4isel_p.h>
+#include <qv4engine_p.h>
+
+QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QQmlJS::V4IR::Module *module)
+ : irModule(module)
+ , stringDataSize(0)
+ , jsClassDataSize(0)
+{
+}
+
+int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
+{
+ QHash<QString, int>::ConstIterator it = stringToId.find(str);
+ if (it != stringToId.end())
+ return *it;
+ stringToId.insert(str, strings.size());
+ strings.append(str);
+ stringDataSize += QV4::CompiledData::String::calculateSize(str);
+ return strings.size() - 1;
+}
+
+int QV4::Compiler::JSUnitGenerator::getStringId(const QString &string) const
+{
+ Q_ASSERT(stringToId.contains(string));
+ return stringToId.value(string);
+}
+
+uint QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name)
+{
+ CompiledData::Lookup l;
+ l.type_and_flags = CompiledData::Lookup::Type_Getter;
+ l.nameIndex = registerString(name);
+ lookups << l;
+ return lookups.size() - 1;
+}
+
+uint QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name)
+{
+ CompiledData::Lookup l;
+ l.type_and_flags = CompiledData::Lookup::Type_Setter;
+ l.nameIndex = registerString(name);
+ lookups << l;
+ return lookups.size() - 1;
+}
+
+uint QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(const QString &name)
+{
+ CompiledData::Lookup l;
+ l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
+ l.nameIndex = registerString(name);
+ lookups << l;
+ return lookups.size() - 1;
+}
+
+int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::V4IR::RegExp *regexp)
+{
+ CompiledData::RegExp re;
+ re.stringIndex = registerString(*regexp->value);
+
+ re.flags = 0;
+ if (regexp->flags & QQmlJS::V4IR::RegExp::RegExp_Global)
+ re.flags |= CompiledData::RegExp::RegExp_Global;
+ if (regexp->flags & QQmlJS::V4IR::RegExp::RegExp_IgnoreCase)
+ re.flags |= CompiledData::RegExp::RegExp_IgnoreCase;
+ if (regexp->flags & QQmlJS::V4IR::RegExp::RegExp_Multiline)
+ re.flags |= CompiledData::RegExp::RegExp_Multiline;
+
+ regexps.append(re);
+ return regexps.size() - 1;
+}
+
+void QV4::Compiler::JSUnitGenerator::registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings)
+{
+ lineNumberMappingsPerFunction.insert(function, mappings);
+}
+
+int QV4::Compiler::JSUnitGenerator::registerJSClass(QQmlJS::V4IR::ExprList *args)
+{
+ // ### re-use existing class definitions.
+
+ QList<CompiledData::JSClassMember> members;
+
+ QQmlJS::V4IR::ExprList *it = args;
+ while (it) {
+ CompiledData::JSClassMember member;
+
+ QQmlJS::V4IR::Name *name = it->expr->asName();
+ it = it->next;
+
+ const bool isData = it->expr->asConst()->value;
+ it = it->next;
+
+ member.nameOffset = registerString(*name->id);
+ member.isAccessor = !isData;
+ members << member;
+
+ if (!isData)
+ it = it->next;
+
+ it = it->next;
+ }
+
+ jsClasses << members;
+ jsClassDataSize += CompiledData::JSClass::calculateSize(members.count());
+ return jsClasses.size() - 1;
+}
+
+QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
+{
+ registerString(irModule->fileName);
+ foreach (QQmlJS::V4IR::Function *f, irModule->functions) {
+ registerString(*f->name);
+ for (int i = 0; i < f->formals.size(); ++i)
+ registerString(*f->formals.at(i));
+ for (int i = 0; i < f->locals.size(); ++i)
+ registerString(*f->locals.at(i));
+ }
+
+ int unitSize = QV4::CompiledData::Unit::calculateSize(strings.size(), irModule->functions.size(), regexps.size(), lookups.size(), jsClasses.count());
+
+ uint functionDataSize = 0;
+ for (int i = 0; i < irModule->functions.size(); ++i) {
+ QQmlJS::V4IR::Function *f = irModule->functions.at(i);
+ functionOffsets.insert(f, functionDataSize + unitSize + stringDataSize);
+
+ int lineNumberMappingCount = 0;
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(f);
+ if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
+ lineNumberMappingCount = lineNumberMapping->count() / 2;
+
+ functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), lineNumberMappingCount);
+ }
+
+ char *data = (char *)malloc(unitSize + functionDataSize + stringDataSize + jsClassDataSize);
+ QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
+
+ memcpy(unit->magic, QV4::CompiledData::magic_str, sizeof(unit->magic));
+ unit->architecture = 0; // ###
+ unit->flags = QV4::CompiledData::Unit::IsJavascript;
+ unit->version = 1;
+ unit->stringTableSize = strings.size();
+ unit->offsetToStringTable = sizeof(QV4::CompiledData::Unit);
+ unit->functionTableSize = irModule->functions.size();
+ unit->offsetToFunctionTable = unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
+ unit->lookupTableSize = lookups.count();
+ unit->offsetToLookupTable = unit->offsetToFunctionTable + unit->functionTableSize * sizeof(uint);
+ unit->regexpTableSize = regexps.size();
+ unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
+ unit->jsClassTableSize = jsClasses.count();
+ unit->offsetToJSClassTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
+ unit->sourceFileIndex = getStringId(irModule->fileName);
+
+ // write strings and string table
+ uint *stringTable = (uint *)(data + unit->offsetToStringTable);
+ char *string = data + unitSize;
+ for (int i = 0; i < strings.size(); ++i) {
+ stringTable[i] = string - data;
+ const QString &qstr = strings.at(i);
+
+ QV4::CompiledData::String *s = (QV4::CompiledData::String*)(string);
+ s->hash = QV4::String::createHashValue(qstr.constData(), qstr.length());
+ s->flags = 0; // ###
+ s->str.ref.atomic.store(-1);
+ s->str.size = qstr.length();
+ s->str.alloc = 0;
+ s->str.capacityReserved = false;
+ s->str.offset = sizeof(QArrayData);
+ memcpy(s + 1, qstr.constData(), (qstr.length() + 1)*sizeof(ushort));
+
+ string += QV4::CompiledData::String::calculateSize(qstr);
+ }
+
+ uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
+ for (uint i = 0; i < irModule->functions.size(); ++i)
+ functionTable[i] = functionOffsets.value(irModule->functions.at(i));
+
+ char *f = data + unitSize + stringDataSize;
+ for (uint i = 0; i < irModule->functions.size(); ++i) {
+ QQmlJS::V4IR::Function *function = irModule->functions.at(i);
+ if (function == irModule->rootFunction)
+ unit->indexOfRootFunction = i;
+
+ const int bytes = writeFunction(f, i, function);
+ f += bytes;
+ }
+
+ CompiledData::Lookup *lookupsToWrite = (CompiledData::Lookup*)(data + unit->offsetToLookupTable);
+ foreach (const CompiledData::Lookup &l, lookups)
+ *lookupsToWrite++ = l;
+
+ CompiledData::RegExp *regexpTable = (CompiledData::RegExp *)(data + unit->offsetToRegexpTable);
+ memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
+
+ // write js classes and js class lookup table
+ uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
+ char *jsClass = data + unitSize + stringDataSize + functionDataSize;
+ for (int i = 0; i < jsClasses.count(); ++i) {
+ jsClassTable[i] = jsClass - data;
+
+ const QList<CompiledData::JSClassMember> members = jsClasses.at(i);
+
+ CompiledData::JSClass *c = reinterpret_cast<CompiledData::JSClass*>(jsClass);
+ c->nMembers = members.count();
+
+ CompiledData::JSClassMember *memberToWrite = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + sizeof(CompiledData::JSClass));
+ foreach (const CompiledData::JSClassMember &member, members)
+ *memberToWrite++ = member;
+
+ jsClass += CompiledData::JSClass::calculateSize(members.count());
+ }
+
+ return unit;
+}
+
+int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction)
+{
+ QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
+
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> >::ConstIterator lineNumberMapping = lineNumberMappingsPerFunction.find(irFunction);
+
+ function->index = index;
+ function->nameIndex = getStringId(*irFunction->name);
+ function->flags = 0;
+ if (irFunction->hasDirectEval)
+ function->flags |= CompiledData::Function::HasDirectEval;
+ if (irFunction->usesArgumentsObject)
+ function->flags |= CompiledData::Function::UsesArgumentsObject;
+ if (irFunction->isStrict)
+ function->flags |= CompiledData::Function::IsStrict;
+ if (irFunction->isNamedExpression)
+ function->flags |= CompiledData::Function::IsNamedExpression;
+ function->nFormals = irFunction->formals.size();
+ function->formalsOffset = sizeof(QV4::CompiledData::Function);
+ function->nLocals = irFunction->locals.size();
+ function->localsOffset = function->formalsOffset + function->nFormals * sizeof(quint32);
+
+ function->nLineNumberMappingEntries = 0;
+ if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd()) {
+ function->nLineNumberMappingEntries = lineNumberMapping->count() / 2;
+ }
+ function->lineNumberMappingOffset = function->localsOffset + function->nLocals * sizeof(quint32);
+
+ function->nInnerFunctions = irFunction->nestedFunctions.size();
+ function->innerFunctionsOffset = function->lineNumberMappingOffset + function->nLineNumberMappingEntries * 2 * sizeof(quint32);
+
+ // write formals
+ quint32 *formals = (quint32 *)(f + function->formalsOffset);
+ for (int i = 0; i < irFunction->formals.size(); ++i)
+ formals[i] = getStringId(*irFunction->formals.at(i));
+
+ // write locals
+ quint32 *locals = (quint32 *)(f + function->localsOffset);
+ for (int i = 0; i < irFunction->locals.size(); ++i)
+ locals[i] = getStringId(*irFunction->locals.at(i));
+
+ // write line number mappings
+ if (function->nLineNumberMappingEntries) {
+ quint32 *mappingsToWrite = (quint32*)(f + function->lineNumberMappingOffset);
+ memcpy(mappingsToWrite, lineNumberMapping->constData(), 2 * function->nLineNumberMappingEntries * sizeof(quint32));
+ }
+
+ // write inner functions
+ quint32 *innerFunctions = (quint32 *)(f + function->innerFunctionsOffset);
+ for (int i = 0; i < irFunction->nestedFunctions.size(); ++i)
+ innerFunctions[i] = functionOffsets.value(irFunction->nestedFunctions.at(i));
+
+ return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries);
+}
+
+
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
new file mode 100644
index 0000000000..6c50073a24
--- /dev/null
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4COMPILER_P_H
+#define QV4COMPILER_P_H
+
+#include <QtCore/qstring.h>
+#include "qv4jsir_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace CompiledData {
+struct Unit;
+struct Lookup;
+struct RegExp;
+struct JSClassMember;
+}
+
+namespace Compiler {
+
+struct JSUnitGenerator {
+ JSUnitGenerator(QQmlJS::V4IR::Module *module);
+
+ QQmlJS::V4IR::Module *irModule;
+
+ int registerString(const QString &str);
+ int getStringId(const QString &string) const;
+
+ uint registerGetterLookup(const QString &name);
+ uint registerSetterLookup(const QString &name);
+ uint registerGlobalGetterLookup(const QString &name);
+
+ int registerRegExp(QQmlJS::V4IR::RegExp *regexp);
+
+ void registerLineNumberMapping(QQmlJS::V4IR::Function *function, const QVector<uint> &mappings);
+
+ int registerJSClass(QQmlJS::V4IR::ExprList *args);
+
+ QV4::CompiledData::Unit *generateUnit();
+ // Returns bytes written
+ int writeFunction(char *f, int index, QQmlJS::V4IR::Function *irFunction);
+
+ QHash<QString, int> stringToId;
+ QStringList strings;
+ int stringDataSize;
+ QHash<QQmlJS::V4IR::Function *, uint> functionOffsets;
+ QList<CompiledData::Lookup> lookups;
+ QVector<CompiledData::RegExp> regexps;
+ QHash<QQmlJS::V4IR::Function *, QVector<uint> > lineNumberMappingsPerFunction;
+ QList<QList<CompiledData::JSClassMember> > jsClasses;
+ int jsClassDataSize;
+};
+
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 5e1fb6f441..8164e439f0 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -52,6 +52,8 @@ QT_BEGIN_NAMESPACE
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret, ret) \
F(LoadValue, loadValue) \
+ F(LoadRuntimeString, loadRuntimeString) \
+ F(LoadRegExp, loadRegExp) \
F(LoadClosure, loadClosure) \
F(MoveTemp, moveTemp) \
F(LoadName, loadName) \
@@ -219,6 +221,16 @@ union Instr
Param value;
Param result;
};
+ struct instr_loadRuntimeString {
+ MOTH_INSTR_HEADER
+ int stringId;
+ Param result;
+ };
+ struct instr_loadRegExp {
+ MOTH_INSTR_HEADER
+ int regExpId;
+ Param result;
+ };
struct instr_moveTemp {
MOTH_INSTR_HEADER
Param source;
@@ -226,28 +238,28 @@ union Instr
};
struct instr_loadClosure {
MOTH_INSTR_HEADER
- QV4::Function *value;
+ int value;
Param result;
};
struct instr_loadName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param result;
};
struct instr_storeName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param source;
};
struct instr_loadProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param base;
Param result;
};
struct instr_storeProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param base;
Param source;
};
@@ -271,7 +283,7 @@ union Instr
MOTH_INSTR_HEADER
ptrdiff_t tryOffset;
ptrdiff_t catchOffset;
- QV4::String *exceptionVarName;
+ int exceptionVarName;
Param exceptionVar;
};
struct instr_callValue {
@@ -283,7 +295,7 @@ union Instr
};
struct instr_callProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
quint32 argc;
quint32 args;
Param base;
@@ -299,7 +311,7 @@ union Instr
};
struct instr_callActivationProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
quint32 argc;
quint32 args;
Param result;
@@ -330,7 +342,7 @@ union Instr
};
struct instr_callBuiltinDeleteMember {
MOTH_INSTR_HEADER
- QV4::String *member;
+ int member;
Param base;
Param result;
};
@@ -342,12 +354,12 @@ union Instr
};
struct instr_callBuiltinDeleteName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param result;
};
struct instr_callBuiltinTypeofMember {
MOTH_INSTR_HEADER
- QV4::String *member;
+ int member;
Param base;
Param result;
};
@@ -359,7 +371,7 @@ union Instr
};
struct instr_callBuiltinTypeofName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param result;
};
struct instr_callBuiltinTypeofValue {
@@ -370,7 +382,7 @@ union Instr
struct instr_callBuiltinPostIncMember {
MOTH_INSTR_HEADER
Param base;
- QV4::String *member;
+ int member;
Param result;
};
struct instr_callBuiltinPostIncSubscript {
@@ -381,7 +393,7 @@ union Instr
};
struct instr_callBuiltinPostIncName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param result;
};
struct instr_callBuiltinPostIncValue {
@@ -392,7 +404,7 @@ union Instr
struct instr_callBuiltinPostDecMember {
MOTH_INSTR_HEADER
Param base;
- QV4::String *member;
+ int member;
Param result;
};
struct instr_callBuiltinPostDecSubscript {
@@ -403,7 +415,7 @@ union Instr
};
struct instr_callBuiltinPostDecName {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param result;
};
struct instr_callBuiltinPostDecValue {
@@ -413,19 +425,19 @@ union Instr
};
struct instr_callBuiltinDeclareVar {
MOTH_INSTR_HEADER
- QV4::String *varName;
+ int varName;
bool isDeletable;
};
struct instr_callBuiltinDefineGetterSetter {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param object;
Param getter;
Param setter;
};
struct instr_callBuiltinDefineProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
Param object;
Param value;
};
@@ -437,7 +449,7 @@ union Instr
};
struct instr_callBuiltinDefineObjectLiteral {
MOTH_INSTR_HEADER
- QV4::InternalClass *internalClass;
+ int internalClassId;
quint32 args;
Param result;
};
@@ -454,7 +466,7 @@ union Instr
};
struct instr_createProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
quint32 argc;
quint32 args;
Param base;
@@ -462,7 +474,7 @@ union Instr
};
struct instr_createActivationProperty {
MOTH_INSTR_HEADER
- QV4::String *name;
+ int name;
quint32 argc;
quint32 args;
Param result;
@@ -528,20 +540,22 @@ union Instr
struct instr_inplaceMemberOp {
MOTH_INSTR_HEADER
QV4::InplaceBinOpMember alu;
- QV4::String *member;
+ int member;
Param base;
Param source;
};
struct instr_inplaceNameOp {
MOTH_INSTR_HEADER
QV4::InplaceBinOpName alu;
- QV4::String *name;
+ int name;
Param source;
};
instr_common common;
instr_ret ret;
instr_loadValue loadValue;
+ instr_loadRuntimeString loadRuntimeString;
+ instr_loadRegExp loadRegExp;
instr_moveTemp moveTemp;
instr_loadClosure loadClosure;
instr_loadName loadName;
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 5c66e7f00c..1da78b5788 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -65,6 +65,36 @@ using namespace QQmlJS;
using namespace QQmlJS::MASM;
using namespace QV4;
+CompilationUnit::~CompilationUnit()
+{
+ UnwindHelper::deregisterFunctions(runtimeFunctions);
+}
+
+void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
+{
+ runtimeFunctions.resize(data->functionTableSize);
+ for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+
+ QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction,
+ (Value (*)(QV4::ExecutionContext *, const uchar *)) codeRefs[i].code().executableAddress(),
+ codeRefs[i].size());
+ runtimeFunctions[i] = runtimeFunction;
+ }
+
+ UnwindHelper::registerFunctions(runtimeFunctions);
+}
+
+QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex)
+{
+ if (functionIndex < 0 || functionIndex >= codeRefs.count())
+ return 0;
+ JSC::ExecutableMemoryHandle *handle = codeRefs[functionIndex].executableMemory();
+ if (!handle)
+ return 0;
+ return handle->chunk();
+}
+
namespace {
class ConvertTemps: protected V4IR::StmtVisitor, protected V4IR::ExprVisitor
{
@@ -178,8 +208,8 @@ const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / s
const Assembler::VoidType Assembler::Void;
-Assembler::Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine)
- : _function(function), _vmFunction(vmFunction), _engine(engine), _nextBlock(0)
+Assembler::Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
+ : _function(function), _isel(isel), _executableAllocator(executableAllocator), _nextBlock(0)
{
}
@@ -251,6 +281,13 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, V4IR::Temp *t)
return Pointer(reg, offset);
}
+Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
+{
+ loadPtr(Address(Assembler::ContextRegister, offsetof(QV4::ExecutionContext, runtimeStrings)), reg);
+ const int id = _isel->registerString(string);
+ return Pointer(reg, id * sizeof(QV4::String*));
+}
+
template <typename Result, typename Source>
void Assembler::copyValue(Result result, Source source)
{
@@ -494,8 +531,7 @@ void Assembler::generateBinOp(V4IR::AluOp operation, V4IR::Temp* target, V4IR::T
binOpFinished.link(this);
}
#if OS(LINUX) || OS(MAC_OS_X)
-static void printDisassembledOutputWithCalls(const char* output, const QHash<void*, const char*>& functions,
- const QVector<String*> &identifiers)
+static void printDisassembledOutputWithCalls(const char* output, const QHash<void*, const char*>& functions)
{
QByteArray processedOutput(output);
for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
@@ -504,13 +540,6 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
ptrString.prepend("0x");
processedOutput = processedOutput.replace(ptrString, it.value());
}
- for (QVector<String*>::ConstIterator it = identifiers.begin(), end = identifiers.end();
- it != end; ++it) {
- QByteArray ptrString = QByteArray::number(quintptr(*it), 16);
- ptrString.prepend("0x");
- QByteArray replacement = "\"" + (*it)->toQString().toUtf8() + "\"";
- processedOutput = processedOutput.replace(ptrString, replacement);
- }
fprintf(stderr, "%s\n", processedOutput.constData());
}
#endif
@@ -524,10 +553,10 @@ void Assembler::recordLineNumber(int lineNumber)
}
-void Assembler::link(QV4::Function *vmFunc)
+JSC::MacroAssemblerCodeRef Assembler::link()
{
- Label endOfCode = label();
#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
+ Label endOfCode = label();
// Let the ARM exception table follow right after that
for (int i = 0, nops = UnwindHelper::unwindInfoSize() / 2; i < nops; ++i)
nop();
@@ -545,17 +574,16 @@ void Assembler::link(QV4::Function *vmFunc)
}
}
- JSC::JSGlobalData dummy(_engine->executableAllocator);
+ JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- vmFunc->codeSize = linkBuffer.offsetOf(endOfCode);
- vmFunc->lineNumberMappings.resize(codeLineNumberMappings.count());
+ QVector<uint> lineNumberMapping(codeLineNumberMappings.count() * 2);
+
for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
- QV4::LineNumberMapping mapping;
- mapping.codeOffset = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
- mapping.lineNumber = codeLineNumberMappings.at(i).lineNumber;
- vmFunc->lineNumberMappings[i] = mapping;
+ lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
+ lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
}
+ _isel->registerLineNumberMapping(_function, lineNumberMapping);
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
@@ -582,6 +610,8 @@ void Assembler::link(QV4::Function *vmFunc)
UnwindHelper::writeARMUnwindInfo(linkBuffer.debugAddress(), linkBuffer.offsetOf(endOfCode));
#endif
+ JSC::MacroAssemblerCodeRef codeRef;
+
static bool showCode = !qgetenv("SHOW_CODE").isNull();
if (showCode) {
#if OS(LINUX) && !defined(Q_OS_ANDROID)
@@ -610,7 +640,7 @@ void Assembler::link(QV4::Function *vmFunc)
name.prepend("IR::Function(0x");
name.append(")");
}
- vmFunc->codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
+ codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
#if (OS(LINUX) && !defined(Q_OS_ANDROID)) || OS(MAC_OS_X)
@@ -620,27 +650,27 @@ void Assembler::link(QV4::Function *vmFunc)
# endif
# if CPU(X86) || CPU(X86_64)
QHash<void*, String*> idents;
- printDisassembledOutputWithCalls(disasmOutput, functions, _vmFunction->identifiers);
+ printDisassembledOutputWithCalls(disasmOutput, functions);
# endif
# if OS(LINUX)
free(disasmOutput);
# endif
#endif
} else {
- vmFunc->codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
+ codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
}
- vmFunc->code = (Value (*)(QV4::ExecutionContext *, const uchar *)) vmFunc->codeRef.code().executableAddress();
+ return codeRef;
}
-InstructionSelection::InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module)
- : EvalInstructionSelection(engine, module)
+InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
+ : EvalInstructionSelection(execAllocator, module)
, _block(0)
, _function(0)
- , _vmFunction(0)
, _as(0)
, _locals(0)
{
+ compilationUnit = new CompilationUnit;
}
InstructionSelection::~InstructionSelection()
@@ -648,16 +678,14 @@ InstructionSelection::~InstructionSelection()
delete _as;
}
-void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *function)
+void InstructionSelection::run(V4IR::Function *function)
{
QVector<Lookup> lookups;
QSet<V4IR::BasicBlock*> reentryBlocks;
qSwap(_function, function);
- qSwap(_vmFunction, vmFunction);
- qSwap(_lookups, lookups);
qSwap(_reentryBlocks, reentryBlocks);
Assembler* oldAssembler = _as;
- _as = new Assembler(_function, _vmFunction, engine());
+ _as = new Assembler(this, _function, executableAllocator);
V4IR::Optimizer opt(_function);
opt.run();
@@ -731,31 +759,32 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
}
}
- _as->link(_vmFunction);
+ JSC::MacroAssemblerCodeRef codeRef =_as->link();
+ codeRefs[_function] = codeRef;
- if (_lookups.size()) {
- _vmFunction->lookups = new Lookup[_lookups.size()];
- memcpy(_vmFunction->lookups, _lookups.constData(), _lookups.size()*sizeof(Lookup));
- }
-
- UnwindHelper::registerFunction(_vmFunction);
-
- qSwap(_vmFunction, vmFunction);
qSwap(_function, function);
- qSwap(_lookups, lookups);
qSwap(_reentryBlocks, reentryBlocks);
qSwap(_locals, locals);
delete _as;
_as = oldAssembler;
}
+QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
+{
+ compilationUnit->data = generateUnit();
+ compilationUnit->codeRefs.resize(irModule->functions.size());
+ int i = 0;
+ foreach (V4IR::Function *irFunction, irModule->functions)
+ compilationUnit->codeRefs[i++] = codeRefs[irFunction];
+ return compilationUnit;
+}
+
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
int argc = prepareVariableArguments(args);
- QV4::String *s = identifier(*func->id);
if (useFastLookups && func->global) {
- uint index = addGlobalLookup(s);
+ uint index = registerGlobalGetterLookup(*func->id);
generateFunctionCall(Assembler::Void, __qmljs_call_global_lookup,
Assembler::ContextRegister, Assembler::PointerToValue(result),
Assembler::TrustedImm32(index),
@@ -764,7 +793,7 @@ void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *
} else {
generateFunctionCall(Assembler::Void, __qmljs_call_activation_property,
Assembler::ContextRegister, Assembler::PointerToValue(result),
- s,
+ Assembler::PointerToString(*func->id),
baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
}
@@ -773,7 +802,7 @@ void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *
void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
@@ -785,7 +814,7 @@ void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Te
void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_name, Assembler::ContextRegister, Assembler::PointerToValue(result), identifier(name));
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_name, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
@@ -797,7 +826,7 @@ void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp
void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_delete_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
@@ -808,7 +837,7 @@ void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Te
void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
{
- generateFunctionCall(Assembler::Void, __qmljs_delete_name, Assembler::ContextRegister, Assembler::PointerToValue(result), identifier(name));
+ generateFunctionCall(Assembler::Void, __qmljs_delete_name, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
@@ -819,7 +848,7 @@ void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::PointerToValue(base), identifier(name));
+ Assembler::PointerToValue(result), Assembler::PointerToValue(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
@@ -831,7 +860,7 @@ void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V
void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_name, Assembler::ContextRegister,
- Assembler::PointerToValue(result), identifier(name));
+ Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result)
@@ -843,7 +872,7 @@ void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR
void InstructionSelection::callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement_member, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
@@ -856,7 +885,7 @@ void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V
void InstructionSelection::callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement_name, Assembler::ContextRegister,
- Assembler::PointerToValue(result), identifier(name));
+ Assembler::PointerToValue(result), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result)
@@ -905,7 +934,7 @@ void InstructionSelection::visitTry(V4IR::Try *t)
generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister,
Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock),
- identifier(*t->exceptionVarName), Assembler::PointerToValue(t->exceptionVar));
+ Assembler::PointerToString(*t->exceptionVarName), Assembler::PointerToValue(t->exceptionVar));
_as->jump(Assembler::ReturnValueRegister);
}
@@ -942,19 +971,19 @@ void InstructionSelection::callBuiltinPopScope()
void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_declare_var, Assembler::ContextRegister,
- Assembler::TrustedImm32(deletable), identifier(name));
+ Assembler::TrustedImm32(deletable), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_getter_setter, Assembler::ContextRegister,
- Assembler::Reference(object), identifier(name), Assembler::PointerToValue(getter), Assembler::PointerToValue(setter));
+ Assembler::Reference(object), Assembler::PointerToString(name), Assembler::PointerToValue(getter), Assembler::PointerToValue(setter));
}
void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_property, Assembler::ContextRegister,
- Assembler::Reference(object), identifier(name), Assembler::PointerToValue(value));
+ Assembler::Reference(object), Assembler::PointerToString(name), Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
@@ -969,15 +998,14 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
{
int argc = 0;
- InternalClass *klass = engine()->emptyClass;
+ const int classId = registerJSClass(args);
+
V4IR::ExprList *it = args;
while (it) {
- V4IR::Name *name = it->expr->asName();
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
- klass = klass->addMember(identifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor);
_as->copyValue(argumentAddressForCall(argc++), it->expr);
@@ -991,7 +1019,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
generateFunctionCall(Assembler::Void, __qmljs_builtin_define_object_literal, Assembler::ContextRegister,
Assembler::PointerToValue(result), baseAddressForCallArguments(),
- Assembler::TrustedImmPtr(klass));
+ Assembler::TrustedImm32(classId));
}
void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
@@ -1026,66 +1054,58 @@ void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targe
void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
{
- Value v = Value::fromString(identifier(str));
- _as->storeValue(v, targetTemp);
+ generateFunctionCall(Assembler::Void, __qmljs_value_from_string, Assembler::PointerToValue(targetTemp), Assembler::PointerToString(str));
}
void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
{
- Value v = Value::fromObject(engine()->newRegExpObject(*sourceRegexp->value,
- sourceRegexp->flags));
- _vmFunction->generatedValues.append(v);
- _as->storeValue(v, targetTemp);
+ int id = registerRegExp(sourceRegexp);
+ generateFunctionCall(Assembler::Void, __qmljs_lookup_runtime_regexp, Assembler::ContextRegister, Assembler::PointerToValue(targetTemp), Assembler::TrustedImm32(id));
}
void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
{
- String *propertyName = identifier(*name->id);
if (useFastLookups && name->global) {
- uint index = addGlobalLookup(propertyName);
+ uint index = registerGlobalGetterLookup(*name->id);
generateLookupCall(index, offsetof(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::PointerToValue(temp));
return;
}
- generateFunctionCall(Assembler::Void, __qmljs_get_activation_property, Assembler::ContextRegister, Assembler::PointerToValue(temp), propertyName);
+ generateFunctionCall(Assembler::Void, __qmljs_get_activation_property, Assembler::ContextRegister, Assembler::PointerToValue(temp), Assembler::PointerToString(*name->id));
}
void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
{
- String *propertyName = identifier(targetName);
generateFunctionCall(Assembler::Void, __qmljs_set_activation_property,
- Assembler::ContextRegister, propertyName, Assembler::Reference(source));
+ Assembler::ContextRegister, Assembler::PointerToString(targetName), Assembler::Reference(source));
}
void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
{
- QV4::Function *vmFunc = vmFunction(closure->value);
- assert(vmFunc);
- generateFunctionCall(Assembler::Void, __qmljs_init_closure, Assembler::ContextRegister, Assembler::PointerToValue(target), Assembler::TrustedImmPtr(vmFunc));
+ int id = irModule->functions.indexOf(closure->value);
+ generateFunctionCall(Assembler::Void, __qmljs_init_closure, Assembler::ContextRegister, Assembler::PointerToValue(target), Assembler::TrustedImm32(id));
}
void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target)
{
if (useFastLookups) {
- QV4::String *s = identifier(name);
- uint index = addLookup(s);
+ uint index = registerGetterLookup(name);
generateLookupCall(index, offsetof(QV4::Lookup, getter), Assembler::PointerToValue(target),
Assembler::Reference(base));
} else {
generateFunctionCall(Assembler::Void, __qmljs_get_property, Assembler::ContextRegister, Assembler::PointerToValue(target),
- Assembler::Reference(base), identifier(name));
+ Assembler::Reference(base), Assembler::PointerToString(name));
}
}
void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
{
if (useFastLookups) {
- QV4::String *s = identifier(targetName);
- uint index = addSetterLookup(s);
+ uint index = registerSetterLookup(targetName);
generateLookupCall(index, offsetof(QV4::Lookup, setter), Assembler::Reference(targetBase), Assembler::Reference(source));
} else {
generateFunctionCall(Assembler::Void, __qmljs_set_property, Assembler::ContextRegister,
Assembler::Reference(targetBase),
- identifier(targetName), Assembler::Reference(source));
+ Assembler::PointerToString(targetName), Assembler::Reference(source));
}
}
@@ -1161,7 +1181,7 @@ void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSour
}
if (op) {
_as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::ContextRegister,
- identifier(targetName), Assembler::Reference(rightSource));
+ Assembler::PointerToString(targetName), Assembler::Reference(rightSource));
}
}
@@ -1215,9 +1235,8 @@ void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source,
}
if (op) {
- String* member = identifier(targetName);
_as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::ContextRegister,
- Assembler::Reference(targetBase), identifier(targetName),
+ Assembler::Reference(targetBase), Assembler::PointerToString(targetName),
Assembler::Reference(source));
}
}
@@ -1228,10 +1247,9 @@ void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name,
assert(base != 0);
int argc = prepareVariableArguments(args);
- QV4::String *s = identifier(name);
if (useFastLookups) {
- uint index = addLookup(s);
+ uint index = registerGetterLookup(name);
generateFunctionCall(Assembler::Void, __qmljs_call_property_lookup,
Assembler::ContextRegister, Assembler::PointerToValue(result),
Assembler::Reference(base), Assembler::TrustedImm32(index),
@@ -1240,7 +1258,7 @@ void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name,
} else {
generateFunctionCall(Assembler::Void, __qmljs_call_property,
Assembler::ContextRegister, Assembler::PointerToValue(result),
- Assembler::Reference(base), s,
+ Assembler::Reference(base), Assembler::PointerToString(name),
baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
}
@@ -1267,22 +1285,13 @@ void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
copyValue(source, target);
}
-String *InstructionSelection::identifier(const QString &s)
-{
- String *str = engine()->newIdentifier(s);
- _vmFunction->identifiers.append(str);
- return str;
-}
-
void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
assert(func != 0);
if (useFastLookups && func->global) {
int argc = prepareVariableArguments(args);
- QV4::String *s = identifier(*func->id);
-
- uint index = addGlobalLookup(s);
+ uint index = registerGlobalGetterLookup(*func->id);
generateFunctionCall(Assembler::Void, __qmljs_construct_global_lookup,
Assembler::ContextRegister, Assembler::PointerToValue(result),
Assembler::TrustedImm32(index),
@@ -1298,7 +1307,7 @@ void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &na
{
int argc = prepareVariableArguments(args);
generateFunctionCall(Assembler::Void, __qmljs_construct_property, Assembler::ContextRegister,
- Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
}
void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
@@ -1441,49 +1450,7 @@ void InstructionSelection::callRuntimeMethodImp(V4IR::Temp *result, const char*
int argc = prepareVariableArguments(args);
_as->generateFunctionCallImp(Assembler::Void, name, method, Assembler::ContextRegister, Assembler::PointerToValue(result),
- identifier(*baseName->id), baseAddressForCallArguments(),
+ Assembler::PointerToString(*baseName->id), baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
}
-
-uint InstructionSelection::addLookup(QV4::String *name)
-{
- uint index = (uint)_lookups.size();
- QV4::Lookup l;
- l.getter = Lookup::getterGeneric;
- for (int i = 0; i < Lookup::Size; ++i)
- l.classList[i] = 0;
- l.level = -1;
- l.index = UINT_MAX;
- l.name = name;
- _lookups.append(l);
- return index;
-}
-
-uint InstructionSelection::addSetterLookup(QV4::String *name)
-{
- uint index = (uint)_lookups.size();
- QV4::Lookup l;
- l.setter = Lookup::setterGeneric;
- for (int i = 0; i < Lookup::Size; ++i)
- l.classList[i] = 0;
- l.level = -1;
- l.index = UINT_MAX;
- l.name = name;
- _lookups.append(l);
- return index;
-}
-
-uint InstructionSelection::addGlobalLookup(QV4::String *name)
-{
- uint index = (uint)_lookups.size();
- QV4::Lookup l;
- l.globalGetter = Lookup::globalGetterGeneric;
- for (int i = 0; i < Lookup::Size; ++i)
- l.classList[i] = 0;
- l.level = -1;
- l.index = UINT_MAX;
- l.name = name;
- _lookups.append(l);
- return index;
-}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 9c91bfb014..84ceb2be4b 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -52,16 +52,32 @@
#include <config.h>
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
+#include <assembler/MacroAssemblerCodeRef.h>
QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace MASM {
+class InstructionSelection;
+
+struct CompilationUnit : public QV4::CompiledData::CompilationUnit
+{
+ virtual ~CompilationUnit();
+
+ virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
+
+ virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int functionIndex);
+
+ // Coderef + execution engine
+
+ QVector<JSC::MacroAssemblerCodeRef> codeRefs;
+};
+
class Assembler : public JSC::MacroAssembler
{
public:
- Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine);
+ Assembler(InstructionSelection *isel, V4IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
#if CPU(X86)
#undef VALUE_FITS_IN_REGISTER
@@ -245,6 +261,10 @@ public:
PointerToValue(V4IR::Temp *value) : value(value) {}
V4IR::Temp *value;
};
+ struct PointerToString {
+ explicit PointerToString(const QString &string) : string(string) {}
+ QString string;
+ };
struct Reference {
Reference(V4IR::Temp *value) : value(value) {}
V4IR::Temp *value;
@@ -274,6 +294,7 @@ public:
void addPatch(DataLabelPtr patch, V4IR::BasicBlock *target);
Pointer loadTempAddress(RegisterID reg, V4IR::Temp *t);
+ Pointer loadStringAddress(RegisterID reg, const QString &string);
void loadArgumentInRegister(RegisterID source, RegisterID dest)
{
@@ -299,6 +320,11 @@ public:
loadArgumentInRegister(addr, dest);
}
}
+ void loadArgumentInRegister(PointerToString temp, RegisterID dest)
+ {
+ Pointer addr = loadStringAddress(dest, temp.string);
+ loadPtr(addr, dest);
+ }
void loadArgumentInRegister(Reference temp, RegisterID dest)
{
@@ -419,6 +445,14 @@ public:
}
template <int StackSlot>
+ void loadArgumentOnStack(PointerToString temp)
+ {
+ Pointer ptr = loadStringAddress(ScratchRegister, temp.string);
+ loadPtr(ptr, ScratchRegister);
+ poke(ScratchRegister, StackSlot);
+ }
+
+ template <int StackSlot>
void loadArgumentOnStack(Reference temp)
{
assert (temp.value);
@@ -746,13 +780,12 @@ public:
return Jump();
}
- void link(QV4::Function *vmFunc);
+ JSC::MacroAssemblerCodeRef link();
void recordLineNumber(int lineNumber);
private:
V4IR::Function *_function;
- QV4::Function *_vmFunction;
QHash<V4IR::BasicBlock *, Label> _addrs;
QHash<V4IR::BasicBlock *, QVector<Jump> > _patches;
QList<CallToLink> _callsToLink;
@@ -766,7 +799,8 @@ private:
QHash<V4IR::BasicBlock *, QVector<DataLabelPtr> > _labelPatches;
V4IR::BasicBlock *_nextBlock;
- QV4::ExecutionEngine *_engine;
+ QV4::ExecutableAllocator *_executableAllocator;
+ InstructionSelection *_isel;
struct CodeLineNumerMapping
{
@@ -781,12 +815,14 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
~InstructionSelection();
- virtual void run(QV4::Function *vmFunction, V4IR::Function *function);
+ virtual void run(V4IR::Function *function);
protected:
+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
+
virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
@@ -864,7 +900,6 @@ protected:
return argumentAddressForCall(0);
}
- QV4::String *identifier(const QString &s);
virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
@@ -888,10 +923,6 @@ private:
#define callRuntimeMethod(result, function, ...) \
callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__)
- uint addLookup(QV4::String *name);
- uint addSetterLookup(QV4::String *name);
- uint addGlobalLookup(QV4::String *name);
-
template <typename Arg1, typename Arg2>
void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
@@ -914,19 +945,20 @@ private:
V4IR::BasicBlock *_block;
V4IR::Function* _function;
- QV4::Function* _vmFunction;
- QVector<QV4::Lookup> _lookups;
Assembler* _as;
QSet<V4IR::BasicBlock*> _reentryBlocks;
int _locals;
+
+ CompilationUnit *compilationUnit;
+ QHash<V4IR::Function*, JSC::MacroAssemblerCodeRef> codeRefs;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module)
- { return new InstructionSelection(engine, module); }
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
+ { return new InstructionSelection(execAllocator, module); }
virtual bool jitCompileRegexps() const
{ return true; }
};
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 813acdecec..807f35ad7d 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -46,6 +46,7 @@
#include <private/qv4debugging_p.h>
#include <private/qv4function_p.h>
#include <private/qv4regexpobject_p.h>
+#include <private/qv4compileddata_p.h>
#undef USE_TYPE_INFO
@@ -187,10 +188,9 @@ private:
}
};
-InstructionSelection::InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module)
- : EvalInstructionSelection(engine, module)
+InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
+ : EvalInstructionSelection(execAllocator, module)
, _function(0)
- , _vmFunction(0)
, _block(0)
, _codeStart(0)
, _codeNext(0)
@@ -198,13 +198,14 @@ InstructionSelection::InstructionSelection(QV4::ExecutionEngine *engine, V4IR::M
, _stackSlotAllocator(0)
, _currentStatement(0)
{
+ compilationUnit = new CompilationUnit;
}
InstructionSelection::~InstructionSelection()
{
}
-void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *function)
+void InstructionSelection::run(V4IR::Function *function)
{
V4IR::BasicBlock *block = 0, *nextBlock = 0;
@@ -218,7 +219,6 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
uchar *codeEnd = codeStart + codeSize;
qSwap(_function, function);
- qSwap(_vmFunction, vmFunction);
qSwap(block, _block);
qSwap(nextBlock, _nextBlock);
qSwap(patches, _patches);
@@ -243,18 +243,17 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
push.value = quint32(locals);
addInstruction(push);
+ QVector<uint> lineNumberMappings;
+ lineNumberMappings.reserve(_function->basicBlocks.size() * 2);
+
for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
_block = _function->basicBlocks[i];
_nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
foreach (V4IR::Stmt *s, _block->statements) {
- if (s->location.isValid()) {
- QV4::LineNumberMapping mapping;
- mapping.codeOffset = _codeNext - _codeStart;
- mapping.lineNumber = s->location.startLine;
- _vmFunction->lineNumberMappings.append(mapping);
- }
+ if (s->location.isValid())
+ lineNumberMappings << _codeNext - _codeStart << s->location.startLine;
if (opt.isInSSA() && s->asTerminator()) {
foreach (const V4IR::Optimizer::SSADeconstructionMove &move,
@@ -272,20 +271,17 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
}
}
+ registerLineNumberMapping(_function, lineNumberMappings);
+
// TODO: patch stack size (the push instruction)
patchJumpAddresses();
- _vmFunction->code = VME::exec;
- _vmFunction->codeData = squeezeCode();
-
- if (QV4::Debugging::Debugger *debugger = engine()->debugger)
- debugger->setPendingBreakpoints(_vmFunction);
+ codeRefs.insert(_function, squeezeCode());
qSwap(_currentStatement, cs);
qSwap(_stackSlotAllocator, stackSlotAllocator);
delete stackSlotAllocator;
qSwap(_function, function);
- qSwap(_vmFunction, vmFunction);
qSwap(block, _block);
qSwap(nextBlock, _nextBlock);
qSwap(patches, _patches);
@@ -297,6 +293,16 @@ void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *functi
delete[] codeStart;
}
+QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
+{
+ compilationUnit->data = generateUnit();
+ compilationUnit->codeRefs.resize(irModule->functions.size());
+ int i = 0;
+ foreach (V4IR::Function *irFunction, irModule->functions)
+ compilationUnit->codeRefs[i++] = codeRefs[irFunction];
+ return compilationUnit;
+}
+
void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
{
Instruction::CallValue call;
@@ -311,7 +317,7 @@ void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name, V
// call the property on the loaded base
Instruction::CallProperty call;
call.base = getParam(base);
- call.name = identifier(name);
+ call.name = registerString(name);
prepareCallArgs(args, call.argc, call.args);
call.result = getResultParam(result);
addInstruction(call);
@@ -342,7 +348,7 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
V4IR::Temp *result)
{
Instruction::CreateActivationProperty create;
- create.name = identifier(*func->id);
+ create.name = registerString(*func->id);
prepareCallArgs(args, create.argc, create.args);
create.result = getResultParam(result);
addInstruction(create);
@@ -352,7 +358,7 @@ void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &na
{
Instruction::CreateProperty create;
create.base = getParam(base);
- create.name = identifier(name);
+ create.name = registerString(name);
prepareCallArgs(args, create.argc, create.args);
create.result = getResultParam(result);
addInstruction(create);
@@ -386,21 +392,16 @@ void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targe
void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
{
- Instruction::LoadValue load;
- load.value = Param::createValue(QV4::Value::fromString(identifier(str)));
+ Instruction::LoadRuntimeString load;
+ load.stringId = registerString(str);
load.result = getResultParam(targetTemp);
addInstruction(load);
}
void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
{
- QV4::Value v = QV4::Value::fromObject(engine()->newRegExpObject(
- *sourceRegexp->value,
- sourceRegexp->flags));
- _vmFunction->generatedValues.append(v);
-
- Instruction::LoadValue load;
- load.value = Param::createValue(v);
+ Instruction::LoadRegExp load;
+ load.regExpId = registerRegExp(sourceRegexp);
load.result = getResultParam(targetTemp);
addInstruction(load);
}
@@ -408,7 +409,7 @@ void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *ta
void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
{
Instruction::LoadName load;
- load.name = identifier(*name->id);
+ load.name = registerString(*name->id);
load.result = getResultParam(temp);
addInstruction(load);
}
@@ -417,16 +418,15 @@ void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QStri
{
Instruction::StoreName store;
store.source = getParam(source);
- store.name = identifier(targetName);
+ store.name = registerString(targetName);
addInstruction(store);
}
void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
{
- QV4::Function *vmFunc = vmFunction(closure->value);
- assert(vmFunc);
+ int id = irModule->functions.indexOf(closure->value);
Instruction::LoadClosure load;
- load.value = vmFunc;
+ load.value = id;
load.result = getResultParam(target);
addInstruction(load);
}
@@ -435,7 +435,7 @@ void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4
{
Instruction::LoadProperty load;
load.base = getParam(base);
- load.name = identifier(name);
+ load.name = registerString(name);
load.result = getResultParam(target);
addInstruction(load);
}
@@ -444,7 +444,7 @@ void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBas
{
Instruction::StoreProperty store;
store.base = getParam(targetBase);
- store.name = identifier(targetName);
+ store.name = registerString(targetName);
store.source = getParam(source);
addInstruction(store);
}
@@ -591,7 +591,7 @@ void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSour
if (op) {
Instruction::InplaceNameOp ieo;
ieo.alu = op;
- ieo.name = identifier(targetName);
+ ieo.name = registerString(targetName);
ieo.source = getParam(rightSource);
addInstruction(ieo);
}
@@ -644,7 +644,7 @@ void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source,
Instruction::InplaceMemberOp imo;
imo.alu = op;
imo.base = getParam(targetBase);
- imo.member = identifier(targetName);
+ imo.member = registerString(targetName);
imo.source = getParam(source);
addInstruction(imo);
}
@@ -730,7 +730,7 @@ void InstructionSelection::visitTry(V4IR::Try *t)
Instruction::EnterTry enterTry;
enterTry.tryOffset = 0;
enterTry.catchOffset = 0;
- enterTry.exceptionVarName = identifier(*t->exceptionVarName);
+ enterTry.exceptionVarName = registerString(*t->exceptionVarName);
enterTry.exceptionVar = getParam(t->exceptionVar);
ptrdiff_t enterTryLoc = addInstruction(enterTry);
@@ -744,7 +744,7 @@ void InstructionSelection::visitTry(V4IR::Try *t)
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
Instruction::CallActivationProperty call;
- call.name = identifier(*func->id);
+ call.name = registerString(*func->id);
prepareCallArgs(args, call.argc, call.args);
call.result = getResultParam(result);
addInstruction(call);
@@ -754,7 +754,7 @@ void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QStri
{
Instruction::CallBuiltinTypeofMember call;
call.base = getParam(base);
- call.member = identifier(name);
+ call.member = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -771,7 +771,7 @@ void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Te
void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
{
Instruction::CallBuiltinTypeofName call;
- call.name = identifier(name);
+ call.name = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -788,7 +788,7 @@ void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QStri
{
Instruction::CallBuiltinDeleteMember call;
call.base = getParam(base);
- call.member = identifier(name);
+ call.member = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -805,7 +805,7 @@ void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Te
void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
{
Instruction::CallBuiltinDeleteName call;
- call.name = identifier(name);
+ call.name = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -822,7 +822,7 @@ void InstructionSelection::callBuiltinPostDecrementMember(V4IR::Temp *base, cons
{
Instruction::CallBuiltinPostDecMember call;
call.base = getParam(base);
- call.member = identifier(name);
+ call.member = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -839,7 +839,7 @@ void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V
void InstructionSelection::callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result)
{
Instruction::CallBuiltinPostDecName call;
- call.name = identifier(name);
+ call.name = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -856,7 +856,7 @@ void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, cons
{
Instruction::CallBuiltinPostIncMember call;
call.base = getParam(base);
- call.member = identifier(name);
+ call.member = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -873,7 +873,7 @@ void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V
void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
{
Instruction::CallBuiltinPostIncName call;
- call.name = identifier(name);
+ call.name = registerString(name);
call.result = getResultParam(result);
addInstruction(call);
}
@@ -932,7 +932,7 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
{
Instruction::CallBuiltinDeclareVar call;
call.isDeletable = deletable;
- call.varName = identifier(name);
+ call.varName = registerString(name);
addInstruction(call);
}
@@ -940,7 +940,7 @@ void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, con
{
Instruction::CallBuiltinDefineGetterSetter call;
call.object = getParam(object);
- call.name = identifier(name);
+ call.name = registerString(name);
call.getter = getParam(getter);
call.setter = getParam(setter);
addInstruction(call);
@@ -950,7 +950,7 @@ void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const Q
{
Instruction::CallBuiltinDefineProperty call;
call.object = getParam(object);
- call.name = identifier(name);
+ call.name = registerString(name);
call.value = getParam(value);
addInstruction(call);
}
@@ -967,15 +967,13 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
{
int argLocation = outgoingArgumentTempStart();
- QV4::InternalClass *klass = engine()->emptyClass;
+ const int classId = registerJSClass(args);
V4IR::ExprList *it = args;
while (it) {
- V4IR::Name *name = it->expr->asName();
it = it->next;
bool isData = it->expr->asConst()->value;
it = it->next;
- klass = klass->addMember(identifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor);
Instruction::MoveTemp move;
move.source = getParam(it->expr);
@@ -997,7 +995,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
}
Instruction::CallBuiltinDefineObjectLiteral call;
- call.internalClass = klass;
+ call.internalClassId = classId;
call.args = outgoingArgumentTempStart();
call.result = getResultParam(result);
addInstruction(call);
@@ -1057,21 +1055,15 @@ void InstructionSelection::patchJumpAddresses()
_addrs.clear();
}
-uchar *InstructionSelection::squeezeCode() const
+QByteArray InstructionSelection::squeezeCode() const
{
int codeSize = _codeNext - _codeStart;
- uchar *squeezed = new uchar[codeSize];
- ::memcpy(squeezed, _codeStart, codeSize);
+ QByteArray squeezed;
+ squeezed.resize(codeSize);
+ ::memcpy(squeezed.data(), _codeStart, codeSize);
return squeezed;
}
-QV4::String *InstructionSelection::identifier(const QString &s)
-{
- QV4::String *str = engine()->newIdentifier(s);
- _vmFunction->identifiers.append(str);
- return str;
-}
-
Param InstructionSelection::getParam(V4IR::Expr *e) {
typedef Param Param;
assert(e);
@@ -1096,3 +1088,20 @@ Param InstructionSelection::getParam(V4IR::Expr *e) {
return Param();
}
}
+
+
+void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
+{
+ runtimeFunctions.resize(data->functionTableSize);
+ for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
+ const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
+
+ QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction,
+ &VME::exec, /*size - doesn't matter for moth*/0);
+ runtimeFunction->codeData = reinterpret_cast<const uchar *>(codeRefs.at(i).constData());
+ runtimeFunctions[i] = runtimeFunction;
+
+ if (QV4::Debugging::Debugger *debugger = engine->debugger)
+ debugger->setPendingBreakpoints(runtimeFunction);
+ }
+}
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index b6e4b43582..c88db6f759 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -56,17 +56,28 @@ namespace Moth {
class StackSlotAllocator;
+struct CompilationUnit : public QV4::CompiledData::CompilationUnit
+{
+ virtual void linkBackendToEngine(QV4::ExecutionEngine *engine);
+
+ QVector<QByteArray> codeRefs;
+
+};
+
+
class Q_QML_EXPORT InstructionSelection:
public V4IR::IRDecoder,
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
~InstructionSelection();
- virtual void run(QV4::Function *vmFunction, V4IR::Function *function);
+ virtual void run(V4IR::Function *function);
protected:
+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
+
virtual void visitJump(V4IR::Jump *);
virtual void visitCJump(V4IR::CJump *);
virtual void visitRet(V4IR::Ret *);
@@ -158,12 +169,9 @@ private:
inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
ptrdiff_t addInstructionHelper(Instr::Type type, Instr &instr);
void patchJumpAddresses();
- uchar *squeezeCode() const;
-
- QV4::String *identifier(const QString &s);
+ QByteArray squeezeCode() const;
V4IR::Function *_function;
- QV4::Function *_vmFunction;
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_nextBlock;
@@ -176,14 +184,17 @@ private:
StackSlotAllocator *_stackSlotAllocator;
V4IR::Stmt *_currentStatement;
+
+ CompilationUnit *compilationUnit;
+ QHash<V4IR::Function *, QByteArray> codeRefs;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module)
- { return new InstructionSelection(engine, module); }
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module)
+ { return new InstructionSelection(execAllocator, module); }
virtual bool jitCompileRegexps() const
{ return false; }
};
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 7194473849..96199b59d2 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -58,17 +58,13 @@ QTextStream qout(stderr, QIODevice::WriteOnly);
using namespace QQmlJS;
using namespace QQmlJS::V4IR;
-EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutionEngine *engine, Module *module)
- : _engine(engine)
+EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module)
+ : QV4::Compiler::JSUnitGenerator(module)
, useFastLookups(true)
+ , executableAllocator(execAllocator)
{
- assert(engine);
+ assert(execAllocator);
assert(module);
-
- createFunctionMapping(0, module->rootFunction);
- foreach (V4IR::Function *f, module->functions) {
- assert(_irToVM.contains(f));
- }
}
EvalInstructionSelection::~EvalInstructionSelection()
@@ -77,39 +73,15 @@ EvalInstructionSelection::~EvalInstructionSelection()
EvalISelFactory::~EvalISelFactory()
{}
-QV4::Function *EvalInstructionSelection::createFunctionMapping(QV4::Function *outer, Function *irFunction)
+QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile()
{
- QV4::Function *vmFunction = _engine->newFunction(irFunction->name ? *irFunction->name : QString());
- _irToVM.insert(irFunction, vmFunction);
-
- vmFunction->hasDirectEval = irFunction->hasDirectEval;
- vmFunction->usesArgumentsObject = irFunction->usesArgumentsObject;
- vmFunction->hasNestedFunctions = !irFunction->nestedFunctions.isEmpty();
- vmFunction->isStrict = irFunction->isStrict;
- vmFunction->isNamedExpression = irFunction->isNamedExpression;
- vmFunction->sourceFile = irFunction->sourceFile;
-
- if (outer)
- outer->addNestedFunction(vmFunction);
-
- foreach (const QString *formal, irFunction->formals)
- if (formal)
- vmFunction->formals.append(_engine->newString(*formal));
- foreach (const QString *local, irFunction->locals)
- if (local)
- vmFunction->locals.append(_engine->newString(*local));
-
- foreach (V4IR::Function *function, irFunction->nestedFunctions)
- createFunctionMapping(vmFunction, function);
-
- return vmFunction;
-}
+ Function *rootFunction = irModule->rootFunction;
+ if (!rootFunction)
+ return 0;
+ foreach (V4IR::Function *f, irModule->functions)
+ run(f);
-QV4::Function *EvalInstructionSelection::vmFunction(Function *f) {
- QV4::Function *function = _irToVM[f];
- if (!function->code)
- run(function, f);
- return function;
+ return backendCompileStep();
}
void IRDecoder::visitMove(V4IR::Move *s)
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 947583a907..6f4b042a09 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -44,6 +44,8 @@
#include "private/qv4global_p.h"
#include "qv4jsir_p.h"
+#include <private/qv4compileddata_p.h>
+#include <private/qv4compiler_p.h>
#include <qglobal.h>
#include <QHash>
@@ -51,39 +53,36 @@
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct ExecutionEngine;
+class ExecutableAllocator;
struct Function;
}
namespace QQmlJS {
-class Q_QML_EXPORT EvalInstructionSelection
+class Q_QML_EXPORT EvalInstructionSelection : public QV4::Compiler::JSUnitGenerator
{
public:
- EvalInstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module);
virtual ~EvalInstructionSelection() = 0;
- QV4::Function *vmFunction(V4IR::Function *f);
+ QV4::CompiledData::CompilationUnit *compile();
void setUseFastLookups(bool b) { useFastLookups = b; }
protected:
- QV4::Function *createFunctionMapping(QV4::Function *outer, V4IR::Function *irFunction);
- QV4::ExecutionEngine *engine() const { return _engine; }
- virtual void run(QV4::Function *vmFunction, V4IR::Function *function) = 0;
+ virtual void run(V4IR::Function *function) = 0;
+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep() = 0;
-private:
- QV4::ExecutionEngine *_engine;
- QHash<V4IR::Function *, QV4::Function *> _irToVM;
protected:
bool useFastLookups;
+ QV4::ExecutableAllocator *executableAllocator;
};
class Q_QML_EXPORT EvalISelFactory
{
public:
virtual ~EvalISelFactory() = 0;
- virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module) = 0;
+ virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module) = 0;
virtual bool jitCompileRegexps() const = 0;
};
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 23b299cbad..74445cc2c8 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -627,6 +627,15 @@ Module::~Module()
}
}
+void Module::setFileName(const QString &name)
+{
+ if (fileName.isEmpty())
+ fileName = name;
+ else {
+ Q_ASSERT(fileName == name);
+ }
+}
+
Function::~Function()
{
// destroy the Stmt::Data blocks manually, because memory pool cleanup won't
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 2d2e11ffda..14daff0fb6 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -672,11 +672,14 @@ struct Q_QML_EXPORT Module {
MemoryPool pool;
QVector<Function *> functions;
Function *rootFunction;
+ QString fileName;
Function *newFunction(const QString &name, Function *outer);
Module() : rootFunction(0) {}
~Module();
+
+ void setFileName(const QString &name);
};
struct Function {
@@ -692,8 +695,6 @@ struct Function {
QVector<Function *> nestedFunctions;
Function *outer;
- QString sourceFile;
-
int insideWithOrCatch;
uint hasDirectEval: 1;
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index ffada86859..989ed5b19f 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -110,6 +110,9 @@ void WithContext::initWithContext(ExecutionContext *p, Object *with)
thisObject = p->thisObject;
outer = p;
lookups = p->lookups;
+ runtimeStrings = p->runtimeStrings;
+ compilationUnit = p->compilationUnit;
+ compiledFunction = p->compiledFunction;
withObject = with;
}
@@ -121,6 +124,9 @@ void CatchContext::initCatchContext(ExecutionContext *p, String *exceptionVarNam
thisObject = p->thisObject;
outer = p;
lookups = p->lookups;
+ runtimeStrings = p->runtimeStrings;
+ compilationUnit = p->compilationUnit;
+ compiledFunction = p->compiledFunction;
this->exceptionVarName = exceptionVarName;
this->exceptionValue = exceptionValue;
@@ -145,8 +151,12 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
activation = 0;
- if (function->function)
- lookups = function->function->lookups;
+ if (function->function) {
+ compilationUnit = function->function->compilationUnit;
+ compiledFunction = function->function->compiledFunction;
+ lookups = compilationUnit->runtimeLookups;
+ runtimeStrings = compilationUnit->runtimeStrings;
+ }
uint argc = argumentCount;
@@ -184,7 +194,10 @@ void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, F
activation = qml;
- lookups = function->function->lookups;
+ compilationUnit = function->function->compilationUnit;
+ compiledFunction = function->function->compiledFunction;
+ lookups = compilationUnit->runtimeLookups;
+ runtimeStrings = compilationUnit->runtimeStrings;
locals = (Value *)(this + 1);
if (function->varCount)
@@ -358,7 +371,7 @@ Value ExecutionContext::getProperty(String *name)
if (hasProperty)
return v;
}
- if (f->function && f->function->isNamedExpression
+ if (f->function && f->function->isNamedExpression()
&& name->isEqualTo(f->function->name))
return Value::fromObject(c->function);
}
@@ -420,7 +433,7 @@ Value ExecutionContext::getPropertyNoThrow(String *name)
if (hasProperty)
return v;
}
- if (f->function && f->function->isNamedExpression
+ if (f->function && f->function->isNamedExpression()
&& name->isEqualTo(f->function->name))
return Value::fromObject(c->function);
}
@@ -485,7 +498,7 @@ Value ExecutionContext::getPropertyAndBase(String *name, Object **base)
return v;
}
}
- if (f->function && f->function->isNamedExpression
+ if (f->function && f->function->isNamedExpression()
&& name->isEqualTo(f->function->name))
return Value::fromObject(c->function);
}
@@ -576,7 +589,6 @@ void ExecutionContext::throwURIError(Value msg)
throwError(Value::fromObject(engine->newURIErrorObject(msg)));
}
-
void SimpleCallContext::initSimpleCallContext(ExecutionEngine *engine)
{
initBaseContext(Type_SimpleCallContext, engine, engine->current);
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index bf1269d2dc..271df3a8c0 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -52,6 +52,12 @@ struct Object;
struct ExecutionEngine;
struct DeclarativeEnvironment;
struct Lookup;
+
+namespace CompiledData {
+struct CompilationUnit;
+struct Function;
+};
+
struct CallContext;
struct Q_QML_EXPORT ExecutionContext
@@ -75,6 +81,9 @@ struct Q_QML_EXPORT ExecutionContext
ExecutionContext *parent;
ExecutionContext *outer;
Lookup *lookups;
+ String **runtimeStrings;
+ CompiledData::CompilationUnit *compilationUnit;
+ const CompiledData::Function *compiledFunction;
ExecutionContext *next; // used in the GC
struct EvalCode
@@ -96,6 +105,9 @@ struct Q_QML_EXPORT ExecutionContext
parent = parentContext;
outer = 0;
lookups = 0;
+ runtimeStrings = 0;
+ compilationUnit = 0;
+ compiledFunction = 0;
currentEvalCode = 0;
interpreterInstructionPointer = 0;
}
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 1b182eac89..5534305068 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -130,7 +130,7 @@ Debugger::ExecutionState Debugger::currentExecutionState(const uchar *code) cons
}
state.function = function;
- state.fileName = function->sourceFile;
+ state.fileName = function->sourceFile();
qptrdiff relativeProgramCounter = code - function->codeData;
state.lineNumber = function->lineNumberForProgramCounter(relativeProgramCounter);
@@ -185,9 +185,11 @@ void Debugger::pauseAndWait()
void Debugger::applyPendingBreakPoints()
{
- foreach (Function *function, _engine->functions) {
- m_pendingBreakPointsToAdd.applyToFunction(function, /*removeBreakPoints*/false);
- m_pendingBreakPointsToRemove.applyToFunction(function, /*removeBreakPoints*/true);
+ foreach (QV4::CompiledData::CompilationUnit *unit, _engine->compilationUnits) {
+ foreach (Function *function, unit->runtimeFunctions) {
+ m_pendingBreakPointsToAdd.applyToFunction(function, /*removeBreakPoints*/false);
+ m_pendingBreakPointsToRemove.applyToFunction(function, /*removeBreakPoints*/true);
+ }
}
for (BreakPoints::ConstIterator it = m_pendingBreakPointsToAdd.constBegin(),
@@ -343,17 +345,19 @@ bool Debugger::BreakPoints::contains(const QString &fileName, int lineNumber) co
void Debugger::BreakPoints::applyToFunction(Function *function, bool removeBreakPoints)
{
- Iterator breakPointsForFile = find(function->sourceFile);
+ Iterator breakPointsForFile = find(function->sourceFile());
if (breakPointsForFile == end())
return;
QList<int>::Iterator breakPoint = breakPointsForFile->begin();
while (breakPoint != breakPointsForFile->end()) {
bool breakPointFound = false;
- for (QVector<LineNumberMapping>::ConstIterator mapping = function->lineNumberMappings.constBegin(),
- end = function->lineNumberMappings.constEnd(); mapping != end; ++mapping) {
- if (mapping->lineNumber == *breakPoint) {
- uchar *codePtr = const_cast<uchar *>(function->codeData) + mapping->codeOffset;
+ const quint32 *lineNumberMappings = function->compiledFunction->lineNumberMapping();
+ for (int i = 0; i < function->compiledFunction->nLineNumberMappingEntries; ++i) {
+ const int codeOffset = lineNumberMappings[i * 2];
+ const int lineNumber = lineNumberMappings[i * 2 + 1];
+ if (lineNumber == *breakPoint) {
+ uchar *codePtr = const_cast<uchar *>(function->codeData) + codeOffset;
QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
instruction->common.breakPoint = !removeBreakPoints;
// Continue setting the next break point.
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 84ea7ca036..b272e69fb0 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -87,7 +87,6 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
, debugger(0)
, globalObject(0)
, globalCode(0)
- , functionsNeedSort(false)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
@@ -284,7 +283,6 @@ ExecutionEngine::~ExecutionEngine()
emptyClass->destroy();
delete bumperPointerAllocator;
delete regExpCache;
- UnwindHelper::deregisterFunctions(functions);
delete regExpAllocator;
delete executableAllocator;
}
@@ -371,14 +369,6 @@ ExecutionContext *ExecutionEngine::pushGlobalContext()
return current;
}
-Function *ExecutionEngine::newFunction(const QString &name)
-{
- Function *f = new Function(this, newIdentifier(name));
- functions.append(f);
- functionsNeedSort = true;
- return f;
-}
-
FunctionObject *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *))
{
BuiltinFunctionOld *f = new (memoryManager) BuiltinFunctionOld(scope, name, code);
@@ -620,7 +610,7 @@ QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit)
if (CallContext *callCtx = c->asCallContext()) {
StackFrame frame;
if (callCtx->function->function)
- frame.source = callCtx->function->function->sourceFile;
+ frame.source = callCtx->function->function->sourceFile();
frame.function = callCtx->function->name->toQString();
frame.line = -1;
frame.column = -1;
@@ -636,7 +626,7 @@ QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit)
if (frameLimit && globalCode) {
StackFrame frame;
- frame.source = globalCode->sourceFile;
+ frame.source = globalCode->sourceFile();
frame.function = globalCode->name->toQString();
frame.line = -1;
frame.column = -1;
@@ -672,14 +662,14 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
while (c) {
if (CallContext *callCtx = c->asCallContext()) {
if (callCtx->function->function)
- base.setUrl(callCtx->function->function->sourceFile);
+ base.setUrl(callCtx->function->function->sourceFile());
break;
}
c = c->parent;
}
if (base.isEmpty() && globalCode)
- base.setUrl(globalCode->sourceFile);
+ base.setUrl(globalCode->sourceFile());
if (base.isEmpty())
return src;
@@ -727,9 +717,6 @@ void ExecutionEngine::markObjects()
c = c->parent;
}
- for (int i = 0; i < functions.size(); ++i)
- functions.at(i)->mark();
-
id_length->mark();
id_prototype->mark();
id_constructor->mark();
@@ -784,14 +771,13 @@ void ExecutionEngine::markObjects()
if (m_qmlExtensions)
m_qmlExtensions->markObjects();
+
+ for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
+ it != end; ++it)
+ (*it)->markObjects();
}
namespace {
- bool functionSortHelper(Function *lhs, Function *rhs)
- {
- return reinterpret_cast<quintptr>(lhs->code) < reinterpret_cast<quintptr>(rhs->code);
- }
-
struct FindHelper
{
bool operator()(Function *function, quintptr pc)
@@ -809,15 +795,15 @@ namespace {
Function *ExecutionEngine::functionForProgramCounter(quintptr pc) const
{
- if (functionsNeedSort) {
- qSort(functions.begin(), functions.end(), functionSortHelper);
- functionsNeedSort = false;
+ for (QSet<QV4::CompiledData::CompilationUnit*>::ConstIterator unitIt = compilationUnits.constBegin(), unitEnd = compilationUnits.constEnd();
+ unitIt != unitEnd; ++unitIt) {
+ const QVector<Function*> &functions = (*unitIt)->runtimeFunctionsSortedByAddress;
+ QVector<Function*>::ConstIterator it = qBinaryFind(functions.constBegin(),
+ functions.constEnd(),
+ pc, FindHelper());
+ if (it != functions.constEnd())
+ return *it;
}
-
- QVector<Function*>::ConstIterator it = qBinaryFind(functions.constBegin(), functions.constEnd(),
- pc, FindHelper());
- if (it != functions.constEnd())
- return *it;
return 0;
}
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 90cc2dd967..88cafe5fa0 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -60,6 +60,9 @@ namespace QV4 {
namespace Debugging {
class Debugger;
} // namespace Debugging
+namespace CompiledData {
+struct CompilationUnit;
+}
}
namespace QV4 {
@@ -202,8 +205,7 @@ struct Q_QML_EXPORT ExecutionEngine
String *id_uintMax;
String *id_name;
- mutable QVector<Function *> functions;
- mutable bool functionsNeedSort;
+ QSet<CompiledData::CompilationUnit*> compilationUnits;
quint32 m_engineId;
@@ -241,8 +243,6 @@ struct Q_QML_EXPORT ExecutionEngine
void pushContext(SimpleCallContext *context);
ExecutionContext *popContext();
- Function *newFunction(const QString &name);
-
FunctionObject *newBuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *));
FunctionObject *newScriptFunction(ExecutionContext *scope, Function *function);
BoundFunction *newBoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs);
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 8c303a21ab..e989d31c1b 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -51,18 +51,41 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
+Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
+ Value (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize)
+ : name(0)
+ , compiledFunction(0)
+ , compilationUnit(0)
+ , code(0)
+ , codeData(0)
+ , codeSize(0)
+{
+ Q_ASSERT(!compilationUnit);
+ compilationUnit = unit;
+ compiledFunction = function;
+
+ name = compilationUnit->runtimeStrings[compiledFunction->nameIndex];
+
+ code = codePtr;
+ codeSize = _codeSize;
+
+ formals.resize(compiledFunction->nFormals);
+ const quint32 *formalsIndices = compiledFunction->formalsTable();
+ for (int i = 0; i < compiledFunction->nFormals; ++i)
+ formals[i] = engine->newString(unit->data->stringAt(formalsIndices[i]));
+
+
+ locals.resize(compiledFunction->nLocals);
+ const quint32 *localsIndices = compiledFunction->localsTable();
+ for (int i = 0; i < compiledFunction->nLocals; ++i)
+ locals[i] = engine->newString(unit->data->stringAt(localsIndices[i]));
+}
+
Function::~Function()
{
- engine->functions.remove(engine->functions.indexOf(this));
- UnwindHelper::deregisterFunction(this);
-
- Q_ASSERT(!refCount);
- delete[] codeData;
- delete[] lookups;
- foreach (Function *f, nestedFunctions)
- f->deref();
}
+
void Function::mark()
{
if (name)
@@ -71,28 +94,45 @@ void Function::mark()
formals.at(i)->mark();
for (int i = 0; i < locals.size(); ++i)
locals.at(i)->mark();
- for (int i = 0; i < generatedValues.size(); ++i)
- if (Managed *m = generatedValues.at(i).asManaged())
- m->mark();
- for (int i = 0; i < identifiers.size(); ++i)
- identifiers.at(i)->mark();
}
namespace QV4 {
-bool operator<(const LineNumberMapping &mapping, qptrdiff pc)
+struct LineNumberMappingHelper
{
- return mapping.codeOffset < pc;
-}
+ const quint32 *table;
+ int lowerBound(int begin, int end, qptrdiff offset) {
+ int middle;
+ int n = int(end - begin);
+ int half;
+
+ while (n > 0) {
+ half = n >> 1;
+ middle = begin + half;
+ if (table[middle * 2] < offset) {
+ begin = middle + 1;
+ n -= half + 1;
+ } else {
+ n = half;
+ }
+ }
+ return begin;
+ }
+};
+
}
int Function::lineNumberForProgramCounter(qptrdiff offset) const
{
- QVector<LineNumberMapping>::ConstIterator it = qLowerBound(lineNumberMappings.begin(), lineNumberMappings.end(), offset);
- if (it != lineNumberMappings.constBegin() && lineNumberMappings.count() > 0)
- --it;
- if (it == lineNumberMappings.constEnd())
+ LineNumberMappingHelper helper;
+ helper.table = compiledFunction->lineNumberMapping();
+ const uint count = compiledFunction->nLineNumberMappingEntries;
+
+ int pos = helper.lowerBound(0, count, offset);
+ if (pos != 0 && count > 0)
+ --pos;
+ if (pos == count)
return -1;
- return it->lineNumber;
+ return helper.table[pos * 2 + 1];
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 612bbb122e..595955a8ec 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -48,8 +48,8 @@
#include <QtCore/qurl.h>
#include <config.h>
-#include <assembler/MacroAssemblerCodeRef.h>
#include "qv4value_def_p.h"
+#include <private/qv4compileddata_p.h>
QT_BEGIN_NAMESPACE
@@ -80,66 +80,30 @@ struct URIErrorPrototype;
struct InternalClass;
struct Lookup;
-struct LineNumberMapping
-{
- quint32 codeOffset;
- int lineNumber;
-};
-
struct Function {
- int refCount;
String *name;
+ const CompiledData::Function *compiledFunction;
+ CompiledData::CompilationUnit *compilationUnit;
Value (*code)(ExecutionContext *, const uchar *);
const uchar *codeData;
- JSC::MacroAssemblerCodeRef codeRef;
quint32 codeSize;
QVector<String *> formals;
QVector<String *> locals;
- QVector<Value> generatedValues;
- QVector<String *> identifiers;
- QVector<Function *> nestedFunctions;
-
- Lookup *lookups;
-
- bool hasNestedFunctions;
- bool hasDirectEval;
- bool usesArgumentsObject;
- bool isStrict;
- bool isNamedExpression;
-
- QString sourceFile;
- QVector<LineNumberMapping> lineNumberMappings;
-
- ExecutionEngine *engine;
-
- Function(ExecutionEngine *engine, String *name)
- : refCount(0)
- , name(name)
- , code(0)
- , codeData(0)
- , codeSize(0)
- , lookups(0)
- , hasNestedFunctions(0)
- , hasDirectEval(false)
- , usesArgumentsObject(false)
- , isStrict(false)
- , isNamedExpression(false)
- , engine(engine)
- {}
+
+ Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
+ Value (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize);
~Function();
- void ref() { ++refCount; }
- void deref() { if (!--refCount) delete this; }
+ inline QString sourceFile() const { return compilationUnit->fileName(); }
- void addNestedFunction(Function *f)
- {
- f->ref();
- nestedFunctions.append(f);
- }
+ inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; }
+ inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
+ inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
- inline bool needsActivation() const { return hasNestedFunctions || hasDirectEval || usesArgumentsObject; }
+ inline bool needsActivation() const
+ { return compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); }
void mark();
@@ -147,7 +111,6 @@ struct Function {
};
}
-Q_DECLARE_TYPEINFO(QV4::LineNumberMapping, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 56281f0530..012318d30f 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -97,7 +97,7 @@ FunctionObject::FunctionObject(ExecutionContext *scope, String *name)
FunctionObject::~FunctionObject()
{
if (function)
- function->deref();
+ function->compilationUnit->deref();
}
Value FunctionObject::newInstance()
@@ -212,10 +212,11 @@ Value FunctionCtor::construct(Managed *that, Value *args, int argc)
QQmlJS::V4IR::Module module;
QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
- QQmlJS::V4IR::Function *irf = cg(QString(), function, fe, &module);
+ cg(QString(), function, fe, &module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
- QV4::Function *vmf = isel->vmFunction(irf);
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module));
+ QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
+ QV4::Function *vmf = compilationUnit->linkToEngine(v4);
return Value::fromObject(v4->newScriptFunction(v4->rootContext, vmf));
}
@@ -327,7 +328,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
{
vtbl = &static_vtbl;
this->function = function;
- this->function->ref();
+ this->function->compilationUnit->ref();
assert(function);
assert(function->code);
@@ -338,8 +339,8 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
MemoryManager::GCBlocker gcBlocker(scope->engine->memoryManager);
needsActivation = function->needsActivation();
- usesArgumentsObject = function->usesArgumentsObject;
- strictMode = function->isStrict;
+ usesArgumentsObject = function->usesArgumentsObject();
+ strictMode = function->isStrict();
formalParameterCount = function->formals.size();
formalParameterList = function->formals.constData();
defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(formalParameterCount));
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 6b279416a3..99a266bd58 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -383,9 +383,9 @@ Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool d
if (!function)
return Value::undefinedValue();
- strictMode = function->isStrict || (ctx->strictMode);
+ strictMode = function->isStrict() || (ctx->strictMode);
- usesArgumentsObject = function->usesArgumentsObject;
+ usesArgumentsObject = function->usesArgumentsObject();
needsActivation = function->needsActivation();
if (strictMode) {
@@ -402,12 +402,22 @@ Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool d
bool cstrict = ctx->strictMode;
ctx->strictMode = strictMode;
+ CompiledData::CompilationUnit * const oldCompilationUnit = ctx->compilationUnit;
+ const CompiledData::Function * const oldCompiledFunction = ctx->compiledFunction;
+ String ** const oldRuntimeStrings = ctx->runtimeStrings;
+ ctx->compilationUnit = function->compilationUnit;
+ ctx->compiledFunction = function->compiledFunction;
+ ctx->runtimeStrings = function->compilationUnit->runtimeStrings;
+
Value result = Value::undefinedValue();
try {
result = function->code(ctx, function->codeData);
} catch (Exception &ex) {
ctx->strictMode = cstrict;
ctx->currentEvalCode = evalCode.next;
+ ctx->compilationUnit = oldCompilationUnit;
+ ctx->compiledFunction = oldCompiledFunction;
+ ctx->runtimeStrings = oldRuntimeStrings;
if (strictMode)
ex.partiallyUnwindContext(parentContext);
throw;
@@ -415,6 +425,9 @@ Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool d
ctx->strictMode = cstrict;
ctx->currentEvalCode = evalCode.next;
+ ctx->compilationUnit = oldCompilationUnit;
+ ctx->compiledFunction = oldCompiledFunction;
+ ctx->runtimeStrings = oldRuntimeStrings;
while (engine->current != parentContext)
engine->popContext();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 5dd4ef2e29..64345559e5 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -119,36 +119,13 @@ void __qmljs_numberToString(QString *result, double num, int radix)
result->prepend(QLatin1Char('-'));
}
-void __qmljs_init_closure(ExecutionContext *ctx, Value *result, Function *clos)
+void __qmljs_init_closure(ExecutionContext *ctx, Value *result, int functionId)
{
+ QV4::Function *clos = ctx->compilationUnit->runtimeFunctions[functionId];
assert(clos);
*result = Value::fromObject(ctx->engine->newScriptFunction(ctx, clos));
}
-Function *__qmljs_register_function(ExecutionContext *ctx, String *name,
- bool hasDirectEval,
- bool usesArgumentsObject, bool isStrict,
- bool hasNestedFunctions,
- String **formals, unsigned formalCount,
- String **locals, unsigned localCount)
-{
- Function *f = ctx->engine->newFunction(name ? name->toQString() : QString());
-
- f->hasDirectEval = hasDirectEval;
- f->usesArgumentsObject = usesArgumentsObject;
- f->isStrict = isStrict;
- f->hasNestedFunctions = hasNestedFunctions;
-
- for (unsigned i = 0; i < formalCount; ++i)
- if (formals[i])
- f->formals.append(formals[i]);
- for (unsigned i = 0; i < localCount; ++i)
- if (locals[i])
- f->locals.append(locals[i]);
-
- return f;
-}
-
void __qmljs_delete_subscript(ExecutionContext *ctx, Value *result, const Value &base, const Value &index)
{
if (Object *o = base.asObject()) {
@@ -1201,8 +1178,9 @@ void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &ob
pd->setSetter(setter ? setter->asFunctionObject() : 0);
}
-void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass)
+void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, int classId)
{
+ QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId];
Object *o = ctx->engine->newObject(klass);
for (int i = 0; i < klass->size; ++i) {
@@ -1272,6 +1250,16 @@ unsigned __qmljs_double_to_uint32(double d)
return Value::toUInt32(d);
}
+void __qmljs_value_from_string(Value *result, String *string)
+{
+ *result = Value::fromString(string);
+}
+
+void __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, Value *result, int id)
+{
+ *result = ctx->compilationUnit->runtimeRegularExpressions[id];
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index bce9508148..5f3f45263c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -124,16 +124,14 @@ void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, QV4
void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, QV4::Value *val);
void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array, QV4::Value *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter);
-void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass);
+void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, int classId);
void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, QV4::Value *result);
+
+void __qmljs_value_from_string(QV4::Value *result, QV4::String *string);
+void __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, QV4::Value *result, int id);
+
// constructors
-void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);
-QV4::Function *__qmljs_register_function(QV4::ExecutionContext *ctx, QV4::String *name,
- bool hasDirectEval,
- bool usesArgumentsObject, bool isStrict,
- bool hasNestedFunctions,
- QV4::String **formals, unsigned formalCount,
- QV4::String **locals, unsigned localCount);
+void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, int functionId);
// strings
Q_QML_EXPORT double __qmljs_string_to_number(const QString &s);
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index bec5f0bfe8..d2d21d4fd5 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -67,8 +67,8 @@ struct QmlBindingWrapper : FunctionObject
{
vtbl = &static_vtbl;
function = f;
- function->ref();
- usesArgumentsObject = function->usesArgumentsObject;
+ function->compilationUnit->ref();
+ usesArgumentsObject = function->usesArgumentsObject();
needsActivation = function->needsActivation();
defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
@@ -163,14 +163,13 @@ void Script::parse()
inheritedLocals.append(*i ? (*i)->toQString() : QString());
RuntimeCodegen cg(scope, strictMode);
- V4IR::Function *globalIRCode = cg(sourceFile, sourceCode, program, &module,
- parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
+ cg(sourceFile, sourceCode, program, &module,
+ parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module));
if (inheritContext)
isel->setUseFastLookups(false);
- if (globalIRCode) {
- vmFunction = isel->vmFunction(globalIRCode);
- }
+ QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
+ vmFunction = compilationUnit->linkToEngine(v4);
}
if (!vmFunction)
@@ -191,20 +190,34 @@ Value Script::run()
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
bool strict = scope->strictMode;
- Lookup *lookups = scope->lookups;
+ Lookup *oldLookups = scope->lookups;
+ CompiledData::CompilationUnit * const oldCompilationUnit = scope->compilationUnit;
+ const CompiledData::Function * const oldCompiledFunction = scope->compiledFunction;
+ String ** const oldRuntimeStrings = scope->runtimeStrings;
- scope->strictMode = vmFunction->isStrict;
- scope->lookups = vmFunction->lookups;
+ scope->strictMode = vmFunction->isStrict();
+ scope->lookups = vmFunction->compilationUnit->runtimeLookups;
+ scope->compilationUnit = vmFunction->compilationUnit;
+ scope->compiledFunction = vmFunction->compiledFunction;
+ scope->runtimeStrings = vmFunction->compilationUnit->runtimeStrings;
QV4::Value result;
try {
result = vmFunction->code(scope, vmFunction->codeData);
} catch (Exception &e) {
scope->strictMode = strict;
- scope->lookups = lookups;
+ scope->lookups = oldLookups;
+ scope->compilationUnit = oldCompilationUnit;
+ scope->compiledFunction = oldCompiledFunction;
+ scope->runtimeStrings = oldRuntimeStrings;
throw;
}
+ scope->lookups = oldLookups;
+ scope->compilationUnit = oldCompilationUnit;
+ scope->compiledFunction = oldCompiledFunction;
+ scope->runtimeStrings = oldRuntimeStrings;
+
return result;
} else {
diff --git a/src/qml/jsruntime/qv4unwindhelper_p-arm.h b/src/qml/jsruntime/qv4unwindhelper_p-arm.h
index dd1f1e4856..8f5febc3d5 100644
--- a/src/qml/jsruntime/qv4unwindhelper_p-arm.h
+++ b/src/qml/jsruntime/qv4unwindhelper_p-arm.h
@@ -79,7 +79,7 @@ static Function *lookupFunction(void *pc)
if (it == allFunctions.end())
return 0;
- quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((*it)->codeRef.code().executableAddress()));
+ quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((void*)(*it)->code));
if (key < codeStart || key >= codeStart + (*it)->codeSize)
return 0;
return *it;
@@ -217,7 +217,7 @@ extern "C" Q_DECL_EXPORT void *__gnu_Unwind_Find_exidx(void *pc, int *entryCount
QV4::Function *function = QT_PREPEND_NAMESPACE(QV4::lookupFunction(pc));
if (function) {
*entryCount = 1;
- void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit(function->codeRef.code().executableAddress()));
+ void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit((void*)function->code));
// At the end of the function we store our synthetic exception table entry.
return (char *)codeStart + function->codeSize;
}
diff --git a/src/qml/jsruntime/qv4unwindhelper_p-dw2.h b/src/qml/jsruntime/qv4unwindhelper_p-dw2.h
index 57615f0999..3a6204f991 100644
--- a/src/qml/jsruntime/qv4unwindhelper_p-dw2.h
+++ b/src/qml/jsruntime/qv4unwindhelper_p-dw2.h
@@ -48,6 +48,7 @@
#include <wtf/Platform.h>
#include <wtf/PageAllocation.h>
#include <ExecutableAllocator.h>
+#include <private/qv4isel_masm_p.h>
#include <QMap>
#include <QMutex>
@@ -126,13 +127,12 @@ UnwindInfo::~UnwindInfo()
static void ensureUnwindInfo(Function *f)
{
- if (!f->codeRef)
+ if (!f->code)
return; // Not a JIT generated function
- JSC::ExecutableMemoryHandle *handle = f->codeRef.executableMemory();
- if (!handle)
+ ExecutableAllocator::ChunkOfPages *chunk = f->compilationUnit->chunkForFunction(f->compiledFunction->index);
+ if (!chunk)
return;
- ExecutableAllocator::ChunkOfPages *chunk = handle->chunk();
// Already registered?
if (chunk->unwindInfo)
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 7fc52ff552..d5416105fa 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -239,6 +239,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
}
#endif
+ QV4::String ** const runtimeStrings = context->runtimeStrings;
context->interpreterInstructionPointer = &code;
#ifdef MOTH_THREADED_INTERPRETER
@@ -259,18 +260,28 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
VALUE(instr.result) = VALUE(instr.value);
MOTH_END_INSTR(LoadValue)
+ MOTH_BEGIN_INSTR(LoadRuntimeString)
+// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
+ VALUE(instr.result) = QV4::Value::fromString(runtimeStrings[instr.stringId]);
+ MOTH_END_INSTR(LoadRuntimeString)
+
+ MOTH_BEGIN_INSTR(LoadRegExp)
+// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
+ VALUE(instr.result) = context->compilationUnit->runtimeRegularExpressions[instr.regExpId];
+ MOTH_END_INSTR(LoadRegExp)
+
MOTH_BEGIN_INSTR(LoadClosure)
__qmljs_init_closure(context, VALUEPTR(instr.result), instr.value);
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
- __qmljs_get_activation_property(context, VALUEPTR(instr.result), instr.name);
+ __qmljs_get_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name]);
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(StoreName)
TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
- __qmljs_set_activation_property(context, instr.name, VALUE(instr.source));
+ __qmljs_set_activation_property(context, runtimeStrings[instr.name], VALUE(instr.source));
MOTH_END_INSTR(StoreName)
MOTH_BEGIN_INSTR(LoadElement)
@@ -282,11 +293,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- __qmljs_get_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name);
+ __qmljs_get_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name]);
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(StoreProperty)
- __qmljs_set_property(context, VALUE(instr.base), instr.name, VALUE(instr.source));
+ __qmljs_set_property(context, VALUE(instr.base), runtimeStrings[instr.name], VALUE(instr.source));
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(Push)
@@ -316,7 +327,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(instr.name->toQString()), instr.args, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
- __qmljs_call_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name, args, instr.argc);
+ __qmljs_call_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name], args, instr.argc);
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallElement)
@@ -329,7 +340,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
Q_ASSERT(instr.args + instr.argc <= stackSize);
TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
QV4::Value *args = stack + instr.args;
- __qmljs_call_activation_property(context, VALUEPTR(instr.result), instr.name, args, instr.argc);
+ __qmljs_call_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], args, instr.argc);
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallBuiltinThrow)
@@ -347,7 +358,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
ex.accept(context);
VALUE(instr.exceptionVar) = ex.value();
try {
- QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(instr.exceptionVarName, ex.value(), context);
+ QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], ex.value(), context);
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
run(catchContext, catchCode, stack, stackSize);
code = catchCode;
@@ -385,7 +396,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinForeachNextPropertyName)
MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
- __qmljs_delete_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ __qmljs_delete_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]);
MOTH_END_INSTR(CallBuiltinDeleteMember)
MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
@@ -393,11 +404,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinDeleteSubscript)
MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
- __qmljs_delete_name(context, VALUEPTR(instr.result), instr.name);
+ __qmljs_delete_name(context, VALUEPTR(instr.result), runtimeStrings[instr.name]);
MOTH_END_INSTR(CallBuiltinDeleteName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofMember)
- __qmljs_builtin_typeof_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ __qmljs_builtin_typeof_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]);
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript)
@@ -405,7 +416,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofSubscript)
MOTH_BEGIN_INSTR(CallBuiltinTypeofName)
- __qmljs_builtin_typeof_name(context, VALUEPTR(instr.result), instr.name);
+ __qmljs_builtin_typeof_name(context, VALUEPTR(instr.result), runtimeStrings[instr.name]);
MOTH_END_INSTR(CallBuiltinTypeofName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofValue)
@@ -413,7 +424,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofValue)
MOTH_BEGIN_INSTR(CallBuiltinPostIncMember)
- __qmljs_builtin_post_increment_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ __qmljs_builtin_post_increment_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]);
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinPostIncSubscript)
@@ -421,7 +432,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofSubscript)
MOTH_BEGIN_INSTR(CallBuiltinPostIncName)
- __qmljs_builtin_post_increment_name(context, VALUEPTR(instr.result), instr.name);
+ __qmljs_builtin_post_increment_name(context, VALUEPTR(instr.result), runtimeStrings[instr.name]);
MOTH_END_INSTR(CallBuiltinTypeofName)
MOTH_BEGIN_INSTR(CallBuiltinPostIncValue)
@@ -429,7 +440,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofValue)
MOTH_BEGIN_INSTR(CallBuiltinPostDecMember)
- __qmljs_builtin_post_decrement_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ __qmljs_builtin_post_decrement_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]);
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinPostDecSubscript)
@@ -437,7 +448,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofSubscript)
MOTH_BEGIN_INSTR(CallBuiltinPostDecName)
- __qmljs_builtin_post_decrement_name(context, VALUEPTR(instr.result), instr.name);
+ __qmljs_builtin_post_decrement_name(context, VALUEPTR(instr.result), runtimeStrings[instr.name]);
MOTH_END_INSTR(CallBuiltinTypeofName)
MOTH_BEGIN_INSTR(CallBuiltinPostDecValue)
@@ -445,15 +456,15 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallBuiltinTypeofValue)
MOTH_BEGIN_INSTR(CallBuiltinDeclareVar)
- __qmljs_builtin_declare_var(context, instr.isDeletable, instr.varName);
+ __qmljs_builtin_declare_var(context, instr.isDeletable, runtimeStrings[instr.varName]);
MOTH_END_INSTR(CallBuiltinDeclareVar)
MOTH_BEGIN_INSTR(CallBuiltinDefineGetterSetter)
- __qmljs_builtin_define_getter_setter(context, VALUE(instr.object), instr.name, VALUEPTR(instr.getter), VALUEPTR(instr.setter));
+ __qmljs_builtin_define_getter_setter(context, VALUE(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.getter), VALUEPTR(instr.setter));
MOTH_END_INSTR(CallBuiltinDefineGetterSetter)
MOTH_BEGIN_INSTR(CallBuiltinDefineProperty)
- __qmljs_builtin_define_property(context, VALUE(instr.object), instr.name, VALUEPTR(instr.value));
+ __qmljs_builtin_define_property(context, VALUE(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.value));
MOTH_END_INSTR(CallBuiltinDefineProperty)
MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
@@ -464,7 +475,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
QV4::Value *args = stack + instr.args;
- __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass);
+ __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClassId);
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
@@ -480,14 +491,14 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_BEGIN_INSTR(CreateProperty)
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
- __qmljs_construct_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name, args, instr.argc);
+ __qmljs_construct_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name], args, instr.argc);
MOTH_END_INSTR(CreateProperty)
MOTH_BEGIN_INSTR(CreateActivationProperty)
TRACE(inline, "property name = %s, args = %d, argc = %d", instr.name->toQString().toUtf8().constData(), instr.args, instr.argc);
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
- __qmljs_construct_activation_property(context, VALUEPTR(instr.result), instr.name, args, instr.argc);
+ __qmljs_construct_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], args, instr.argc);
MOTH_END_INSTR(CreateActivationProperty)
MOTH_BEGIN_INSTR(Jump)
@@ -560,13 +571,13 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_BEGIN_INSTR(InplaceMemberOp)
instr.alu(context,
VALUE(instr.base),
- instr.member,
+ runtimeStrings[instr.member],
VALUE(instr.source));
MOTH_END_INSTR(InplaceMemberOp)
MOTH_BEGIN_INSTR(InplaceNameOp)
TRACE(name, "%s", instr.name->toQString().toUtf8().constData());
- instr.alu(context, instr.name, VALUE(instr.source));
+ instr.alu(context, runtimeStrings[instr.name], VALUE(instr.source));
MOTH_END_INSTR(InplaceNameOp)
#ifdef MOTH_THREADED_INTERPRETER
diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp
index 225a4f11fb..0244afab34 100644
--- a/tools/v4/main.cpp
+++ b/tools/v4/main.cpp
@@ -206,11 +206,13 @@ int main(int argc, char *argv[])
QV4::Script script(ctx, code, fn);
script.parseAsBinding = runAsQml;
script.parse();
+ script.function()->compilationUnit->ref();
QV4::Value result = script.run();
if (!result.isUndefined()) {
if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl;
}
+ script.function()->compilationUnit->deref();
} catch (QV4::Exception& ex) {
ex.accept(ctx);
showException(ctx, ex);