~ubuntu-branches/ubuntu/vivid/qtdeclarative-opensource-src/vivid

« back to all changes in this revision

Viewing changes to .pc/QML-Compilation-unit-caching-and-JIT-changes.patch/src/qml/jsruntime/qv4script.cpp

  • Committer: Package Import Robot
  • Author(s): Ricardo Mendoza, Ricardo Mendoza, Timo Jyrinki
  • Date: 2015-02-03 14:51:20 UTC
  • Revision ID: package-import@ubuntu.com-20150203145120-bfmnmoflj3oipxga
Tags: 5.3.2-3ubuntu3
[ Ricardo Mendoza ]
* debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch
  - Implement QV4 JIT cache to reduce application startup speed by
    removing unnecessary compiler/assembler runs. This can be enabled
    by exporting QV4_ENABLE_JIT_CACHE=1.

[ Timo Jyrinki ]
* Update symbols

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qv4script_p.h"
 
43
#include "qv4mm_p.h"
 
44
#include "qv4functionobject_p.h"
 
45
#include "qv4function_p.h"
 
46
#include "qv4context_p.h"
 
47
#include "qv4debugging_p.h"
 
48
#include "qv4scopedvalue_p.h"
 
49
 
 
50
#include <private/qqmljsengine_p.h>
 
51
#include <private/qqmljslexer_p.h>
 
52
#include <private/qqmljsparser_p.h>
 
53
#include <private/qqmljsast_p.h>
 
54
#include <private/qqmlengine_p.h>
 
55
#include <qv4jsir_p.h>
 
56
#include <qv4codegen_p.h>
 
57
#include <private/qqmlcontextwrapper_p.h>
 
58
 
 
59
#include <QtCore/QDebug>
 
60
#include <QtCore/QString>
 
61
 
 
62
using namespace QV4;
 
63
 
 
64
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
 
65
    : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
 
66
    , qml(qml)
 
67
    , qmlContext(0)
 
68
{
 
69
    Q_ASSERT(scope->inUse);
 
70
 
 
71
    setVTable(staticVTable());
 
72
    function = f;
 
73
    if (function)
 
74
        function->compilationUnit->ref();
 
75
    needsActivation = function ? function->needsActivation() : false;
 
76
 
 
77
    Scope s(scope);
 
78
    ScopedValue protectThis(s, this);
 
79
 
 
80
    defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
 
81
 
 
82
    qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
 
83
    scope->engine->popContext();
 
84
}
 
85
 
 
86
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
 
87
    : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
 
88
    , qml(qml)
 
89
    , qmlContext(0)
 
90
{
 
91
    Q_ASSERT(scope->inUse);
 
92
 
 
93
    setVTable(staticVTable());
 
94
    function = 0;
 
95
    needsActivation = false;
 
96
 
 
97
    Scope s(scope);
 
98
    ScopedValue protectThis(s, this);
 
99
 
 
100
    defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
 
101
 
 
102
    qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
 
103
    scope->engine->popContext();
 
104
}
 
105
 
 
106
ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
 
107
{
 
108
    ExecutionEngine *engine = that->engine();
 
109
    CHECK_STACK_LIMITS(engine);
 
110
 
 
111
    Scope scope(engine);
 
112
    QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
 
113
    if (!This->function)
 
114
        return QV4::Encode::undefined();
 
115
 
 
116
    CallContext *ctx = This->qmlContext;
 
117
    std::fill(ctx->locals, ctx->locals + ctx->function->varCount(), Primitive::undefinedValue());
 
118
    engine->pushContext(ctx);
 
119
    ScopedValue result(scope, This->function->code(ctx, This->function->codeData));
 
120
    engine->popContext();
 
121
 
 
122
    return result.asReturnedValue();
 
123
}
 
124
 
 
125
void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
 
126
{
 
127
    QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
 
128
    if (wrapper->qml)
 
129
        wrapper->qml->mark(e);
 
130
    FunctionObject::markObjects(m, e);
 
131
    if (wrapper->qmlContext)
 
132
        wrapper->qmlContext->mark(e);
 
133
}
 
134
 
 
135
static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex)
 
136
{
 
137
    QV4::CallContext *signalEmittingContext = ctx->parent->asCallContext();
 
138
    Q_ASSERT(signalEmittingContext);
 
139
    return signalEmittingContext->argument(parameterIndex);
 
140
}
 
141
 
 
142
Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error)
 
143
{
 
144
    ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine);
 
145
    QV4::Scope valueScope(engine);
 
146
    QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine->v8Engine, qmlContext, scopeObject));
 
147
    QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (engine->memoryManager) QV4::QmlBindingWrapper(engine->rootContext, qmlScopeObject));
 
148
 
 
149
    if (!signalParameters.isEmpty()) {
 
150
        if (error)
 
151
            QQmlPropertyCache::signalParameterStringForJS(qmlContext->engine, signalParameters, error);
 
152
        QV4::ScopedProperty p(valueScope);
 
153
        QV4::ScopedString s(valueScope);
 
154
        int index = 0;
 
155
        foreach (const QByteArray &param, signalParameters) {
 
156
            p->setGetter(new (engine->memoryManager) QV4::IndexedBuiltinFunction(wrapper->context(), index++, signalParameterGetter));
 
157
            p->setSetter(0);
 
158
            s = engine->newString(QString::fromUtf8(param));
 
159
            qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
 
160
        }
 
161
    }
 
162
 
 
163
    QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapper->context(), runtimeFunction));
 
164
    return function->asReturned<FunctionObject>();
 
165
}
 
166
 
 
167
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
 
168
 
 
169
struct CompilationUnitHolder : public QV4::Object
 
170
{
 
171
    V4_OBJECT
 
172
 
 
173
    CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit)
 
174
        : Object(engine)
 
175
        , unit(unit)
 
176
    {
 
177
        unit->ref();
 
178
        setVTable(staticVTable());
 
179
    }
 
180
    ~CompilationUnitHolder()
 
181
    {
 
182
        unit->deref();
 
183
    }
 
184
 
 
185
    static void destroy(Managed *that)
 
186
    {
 
187
        static_cast<CompilationUnitHolder*>(that)->~CompilationUnitHolder();
 
188
    }
 
189
 
 
190
    QV4::CompiledData::CompilationUnit *unit;
 
191
};
 
192
 
 
193
DEFINE_OBJECT_VTABLE(CompilationUnitHolder);
 
194
 
 
195
Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit)
 
196
    : line(0), column(0), scope(v4->rootContext), strictMode(false), inheritContext(true), parsed(false)
 
197
    , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true)
 
198
{
 
199
    parsed = true;
 
200
 
 
201
    if (compilationUnit) {
 
202
        vmFunction = compilationUnit->linkToEngine(v4);
 
203
        Q_ASSERT(vmFunction);
 
204
        Scope valueScope(v4);
 
205
        ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
 
206
        compilationUnitHolder = holder.asReturnedValue();
 
207
    } else
 
208
        vmFunction = 0;
 
209
}
 
210
 
 
211
Script::~Script()
 
212
{
 
213
}
 
214
 
 
215
void Script::parse()
 
216
{
 
217
    if (parsed)
 
218
        return;
 
219
 
 
220
    using namespace QQmlJS;
 
221
 
 
222
    parsed = true;
 
223
 
 
224
    ExecutionEngine *v4 = scope->engine;
 
225
    Scope valueScope(v4);
 
226
 
 
227
    MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
 
228
 
 
229
    IR::Module module(v4->debugger != 0);
 
230
 
 
231
    QQmlJS::Engine ee, *engine = &ee;
 
232
    Lexer lexer(engine);
 
233
    lexer.setCode(sourceCode, line, parseAsBinding);
 
234
    Parser parser(engine);
 
235
 
 
236
    const bool parsed = parser.parseProgram();
 
237
 
 
238
    foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
 
239
        if (m.isError()) {
 
240
            scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
 
241
            return;
 
242
        } else {
 
243
            qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
 
244
                      << ": warning: " << m.message;
 
245
        }
 
246
    }
 
247
 
 
248
    if (parsed) {
 
249
        using namespace AST;
 
250
        Program *program = AST::cast<Program *>(parser.rootNode());
 
251
        if (!program) {
 
252
            // if parsing was successful, and we have no program, then
 
253
            // we're done...:
 
254
            return;
 
255
        }
 
256
 
 
257
        QStringList inheritedLocals;
 
258
        if (inheritContext) {
 
259
            CallContext *ctx = scope->asCallContext();
 
260
            if (ctx) {
 
261
                for (String * const *i = ctx->variables(), * const *ei = i + ctx->variableCount(); i < ei; ++i)
 
262
                    inheritedLocals.append(*i ? (*i)->toQString() : QString());
 
263
            }
 
264
        }
 
265
 
 
266
        RuntimeCodegen cg(scope, strictMode);
 
267
        cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals);
 
268
        if (v4->hasException)
 
269
            return;
 
270
 
 
271
        QV4::Compiler::JSUnitGenerator jsGenerator(&module);
 
272
        QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
 
273
        if (inheritContext)
 
274
            isel->setUseFastLookups(false);
 
275
        QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
 
276
        vmFunction = compilationUnit->linkToEngine(v4);
 
277
        ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
 
278
        compilationUnitHolder = holder.asReturnedValue();
 
279
    }
 
280
 
 
281
    if (!vmFunction) {
 
282
        // ### FIX file/line number
 
283
        Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
 
284
        v4->currentContext()->throwError(error);
 
285
    }
 
286
}
 
287
 
 
288
ReturnedValue Script::run()
 
289
{
 
290
    struct ContextStateSaver {
 
291
        ExecutionContext *savedContext;
 
292
        bool strictMode;
 
293
        Lookup *lookups;
 
294
        CompiledData::CompilationUnit *compilationUnit;
 
295
 
 
296
        ContextStateSaver(ExecutionContext *context)
 
297
            : savedContext(context)
 
298
            , strictMode(context->strictMode)
 
299
            , lookups(context->lookups)
 
300
            , compilationUnit(context->compilationUnit)
 
301
        {}
 
302
 
 
303
        ~ContextStateSaver()
 
304
        {
 
305
            savedContext->strictMode = strictMode;
 
306
            savedContext->lookups = lookups;
 
307
            savedContext->compilationUnit = compilationUnit;
 
308
        }
 
309
    };
 
310
 
 
311
    if (!parsed)
 
312
        parse();
 
313
    if (!vmFunction)
 
314
        return Encode::undefined();
 
315
 
 
316
    QV4::ExecutionEngine *engine = scope->engine;
 
317
    QV4::Scope valueScope(engine);
 
318
 
 
319
    if (qml.isUndefined()) {
 
320
        TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
 
321
 
 
322
        ExecutionContextSaver ctxSaver(scope);
 
323
        ContextStateSaver stateSaver(scope);
 
324
        scope->strictMode = vmFunction->isStrict();
 
325
        scope->lookups = vmFunction->compilationUnit->runtimeLookups;
 
326
        scope->compilationUnit = vmFunction->compilationUnit;
 
327
 
 
328
        return vmFunction->code(scope, vmFunction->codeData);
 
329
    } else {
 
330
        ScopedObject qmlObj(valueScope, qml.value());
 
331
        FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj);
 
332
        ScopedCallData callData(valueScope, 0);
 
333
        callData->thisObject = Primitive::undefinedValue();
 
334
        return f->call(callData);
 
335
    }
 
336
}
 
337
 
 
338
Function *Script::function()
 
339
{
 
340
    if (!parsed)
 
341
        parse();
 
342
    return vmFunction;
 
343
}
 
344
 
 
345
QV4::CompiledData::CompilationUnit *Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors)
 
346
{
 
347
    using namespace QQmlJS;
 
348
    using namespace QQmlJS::AST;
 
349
 
 
350
    QQmlJS::Engine ee;
 
351
    QQmlJS::Lexer lexer(&ee);
 
352
    lexer.setCode(source, /*line*/1, /*qml mode*/true);
 
353
    QQmlJS::Parser parser(&ee);
 
354
 
 
355
    parser.parseProgram();
 
356
 
 
357
    QList<QQmlError> errors;
 
358
 
 
359
    foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
 
360
        if (m.isWarning()) {
 
361
            qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message));
 
362
            continue;
 
363
        }
 
364
 
 
365
        QQmlError error;
 
366
        error.setUrl(url);
 
367
        error.setDescription(m.message);
 
368
        error.setLine(m.loc.startLine);
 
369
        error.setColumn(m.loc.startColumn);
 
370
        errors << error;
 
371
    }
 
372
 
 
373
    if (!errors.isEmpty()) {
 
374
        if (reportedErrors)
 
375
            *reportedErrors << errors;
 
376
        return 0;
 
377
    }
 
378
 
 
379
    Program *program = AST::cast<Program *>(parser.rootNode());
 
380
    if (!program) {
 
381
        // if parsing was successful, and we have no program, then
 
382
        // we're done...:
 
383
        return 0;
 
384
    }
 
385
 
 
386
    QQmlJS::Codegen cg(/*strict mode*/false);
 
387
    cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode);
 
388
    errors = cg.qmlErrors();
 
389
    if (!errors.isEmpty()) {
 
390
        if (reportedErrors)
 
391
            *reportedErrors << errors;
 
392
        return 0;
 
393
    }
 
394
 
 
395
    QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator));
 
396
    isel->setUseFastLookups(false);
 
397
    return isel->compile(/*generate unit data*/false);
 
398
}
 
399
 
 
400
ReturnedValue Script::qmlBinding()
 
401
{
 
402
    if (!parsed)
 
403
        parse();
 
404
    ExecutionEngine *v4 = scope->engine;
 
405
    Scope valueScope(v4);
 
406
    ScopedObject qmlObj(valueScope, qml.value());
 
407
    ScopedObject v(valueScope, new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj));
 
408
    return v.asReturnedValue();
 
409
}
 
410
 
 
411
QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine,  const QString &script, ObjectRef scopeObject)
 
412
{
 
413
    QV4::Scope scope(engine);
 
414
    QV4::Script qmlScript(engine, scopeObject, script, QString());
 
415
 
 
416
    QV4::ExecutionContext *ctx = engine->currentContext();
 
417
    qmlScript.parse();
 
418
    QV4::ScopedValue result(scope);
 
419
    if (!scope.engine->hasException)
 
420
        result = qmlScript.run();
 
421
    if (scope.engine->hasException) {
 
422
        ctx->catchException();
 
423
        return Encode::undefined();
 
424
    }
 
425
    return result.asReturnedValue();
 
426
}