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