diff options
author | Simon Hausmann <[email protected]> | 2013-08-20 16:54:29 +0200 |
---|---|---|
committer | Simon Hausmann <[email protected]> | 2013-08-20 16:54:29 +0200 |
commit | 461892e492e0bef399714557498380703b3e029b (patch) | |
tree | ad82e1ae8286bbe650b2ee19ad393a4ab8996bb1 /src/qml/compiler | |
parent | a71e35a95c9f352db91fb82d8a564d01ba961341 (diff) | |
parent | 90aaff37be419ca1f1da40df64424c0d88bfaf19 (diff) |
Merge branch 'wip/v4' of ssh://codereview.qt-project.org/qt/qtdeclarative into dev
Conflicts:
src/qml/compiler/qv4codegen.cpp
src/qml/compiler/qv4codegen_p.h
src/qml/compiler/qv4isel_moth.cpp
src/qml/jsruntime/qv4context_p.h
src/qml/jsruntime/qv4functionobject.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
src/qml/jsruntime/qv4script.cpp
sync.profile
Change-Id: I1d785e2134bffac9553a1c16eed12816cbd1ad2c
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/compiler.pri | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 14 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 157 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 354 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 313 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 99 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 62 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 247 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 62 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 139 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 27 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 50 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 21 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 5 |
16 files changed, 1252 insertions, 312 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; |