2013-05-22 11:49:27 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
** Contact: http://www.qt.io/licensing/
|
2013-05-22 11:49:27 +00:00
|
|
|
**
|
2013-06-24 11:50:51 +00:00
|
|
|
** This file is part of the QtQml module of the Qt Toolkit.
|
2013-05-22 11:49:27 +00:00
|
|
|
**
|
2014-08-22 06:13:59 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
2013-05-22 11:49:27 +00:00
|
|
|
** 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
|
2015-01-28 11:55:39 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
2013-05-22 11:49:27 +00:00
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-08-22 06:13:59 +00:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2013-05-22 11:49:27 +00:00
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2013-05-22 11:49:27 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "qv4script_p.h"
|
2015-02-12 20:16:42 +00:00
|
|
|
#include <private/qv4mm_p.h>
|
2013-05-22 11:49:27 +00:00
|
|
|
#include "qv4functionobject_p.h"
|
|
|
|
#include "qv4function_p.h"
|
|
|
|
#include "qv4context_p.h"
|
|
|
|
#include "qv4debugging_p.h"
|
2015-07-27 13:33:43 +00:00
|
|
|
#include "qv4profiling_p.h"
|
2013-09-05 11:22:23 +00:00
|
|
|
#include "qv4scopedvalue_p.h"
|
2013-05-22 11:49:27 +00:00
|
|
|
|
|
|
|
#include <private/qqmljsengine_p.h>
|
|
|
|
#include <private/qqmljslexer_p.h>
|
|
|
|
#include <private/qqmljsparser_p.h>
|
|
|
|
#include <private/qqmljsast_p.h>
|
2013-10-30 15:49:32 +00:00
|
|
|
#include <private/qqmlengine_p.h>
|
2015-06-11 14:35:11 +00:00
|
|
|
#include <private/qv4profiling_p.h>
|
2013-05-22 11:49:27 +00:00
|
|
|
#include <qv4jsir_p.h>
|
|
|
|
#include <qv4codegen_p.h>
|
2014-04-03 07:38:48 +00:00
|
|
|
#include <private/qqmlcontextwrapper_p.h>
|
2013-05-22 11:49:27 +00:00
|
|
|
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/QString>
|
|
|
|
|
2014-11-07 01:06:42 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
namespace QV4 {
|
|
|
|
namespace Heap {
|
|
|
|
|
|
|
|
struct CompilationUnitHolder : Object {
|
|
|
|
inline CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit);
|
|
|
|
|
|
|
|
QQmlRefPointer<CompiledData::CompilationUnit> unit;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
struct CompilationUnitHolder : public Object
|
|
|
|
{
|
|
|
|
V4_OBJECT2(CompilationUnitHolder, Object)
|
2014-11-13 20:38:25 +00:00
|
|
|
V4_NEEDS_DESTROY
|
2014-11-07 01:06:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
inline
|
|
|
|
Heap::CompilationUnitHolder::CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit)
|
|
|
|
: Heap::Object(engine)
|
|
|
|
, unit(unit)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
2013-05-22 11:49:27 +00:00
|
|
|
using namespace QV4;
|
|
|
|
|
2014-11-07 01:06:42 +00:00
|
|
|
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
|
|
|
|
DEFINE_OBJECT_VTABLE(CompilationUnitHolder);
|
|
|
|
|
2015-06-15 13:52:51 +00:00
|
|
|
Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml)
|
2015-04-26 07:22:17 +00:00
|
|
|
: Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false)
|
2014-11-10 15:06:43 +00:00
|
|
|
, qml(qml->d())
|
2013-05-22 12:30:57 +00:00
|
|
|
{
|
2014-04-05 18:23:20 +00:00
|
|
|
Q_ASSERT(scope->inUse());
|
2013-11-14 13:53:28 +00:00
|
|
|
|
2014-05-08 19:29:56 +00:00
|
|
|
function = f;
|
|
|
|
if (function)
|
2014-10-04 15:18:15 +00:00
|
|
|
function->compilationUnit->addref();
|
2013-11-14 13:53:28 +00:00
|
|
|
|
|
|
|
Scope s(scope);
|
2015-06-12 11:07:39 +00:00
|
|
|
Scoped<QV4::QmlBindingWrapper> protectThis(s, this);
|
2013-11-14 13:53:28 +00:00
|
|
|
|
2015-06-12 11:07:39 +00:00
|
|
|
this->scope = scope->newQmlContext(qml);
|
|
|
|
internalClass->engine->popContext();
|
2013-08-06 14:41:28 +00:00
|
|
|
}
|
Fix crashes when running tst_qqmlecmascript::importScripts with aggressive gc
In the case of imported JavaScript files, it may happen that we parse the JS once
and then re-use it across different places where it is imported. That means we
parse and compile the JS once, keep the QV4::Script around and call it as a function
closure with different qml global objects (contexts), depending on where it is
imported from.
In this situation it is possible that the QV4::Script's run() is called once, a
new function object is created, we call it to return the JS library to "eval"
itself into the qml scope and afterwards it may happen that the function object
is garbage collected. It is at this point possible that the compilation unit's
refcount therefore also drops to zero, and thus subsequent calls to
QV4::Script::run() that create new QQmlBinding objects will access a dangling
compilationUnit pointer.
This patch fixes that by making QV4::Script - which is holding a QV4::Function
pointer - also have a persistent, which maintainers a refcount on the
compilation unit. If the script dies, the persistent will get collected and
the last deref will delete the unit. A script can however outlive the engine,
but PersistentValue has the mechanism built in to free itself on engine
destruction, which will also deref the unit accordingly.
Change-Id: I0a7f4e64497bde423ffa55c705af55cdb7d29cf2
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2013-08-26 13:25:47 +00:00
|
|
|
|
2015-06-15 13:52:51 +00:00
|
|
|
Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml)
|
2015-04-26 07:22:17 +00:00
|
|
|
: Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false)
|
2014-11-10 15:06:43 +00:00
|
|
|
, qml(qml->d())
|
2013-09-13 11:43:15 +00:00
|
|
|
{
|
2014-04-05 18:23:20 +00:00
|
|
|
Q_ASSERT(scope->inUse());
|
2013-11-14 13:53:28 +00:00
|
|
|
|
|
|
|
Scope s(scope);
|
2015-06-12 11:07:39 +00:00
|
|
|
Scoped<QV4::QmlBindingWrapper> protectThis(s, this);
|
2013-09-13 11:43:15 +00:00
|
|
|
|
2015-06-12 11:07:39 +00:00
|
|
|
this->scope = scope->newQmlContext(qml);
|
|
|
|
internalClass->engine->popContext();
|
2013-09-13 11:43:15 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 14:35:11 +00:00
|
|
|
ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData)
|
2013-08-06 14:41:28 +00:00
|
|
|
{
|
2015-06-12 11:07:39 +00:00
|
|
|
const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that);
|
2015-06-11 14:35:11 +00:00
|
|
|
ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
|
|
|
|
if (v4->hasException)
|
|
|
|
return Encode::undefined();
|
|
|
|
CHECK_STACK_LIMITS(v4);
|
|
|
|
|
|
|
|
Scope scope(v4);
|
|
|
|
QV4::Function *f = This->function();
|
|
|
|
if (!f)
|
2014-03-31 13:07:18 +00:00
|
|
|
return QV4::Encode::undefined();
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2015-06-11 14:35:11 +00:00
|
|
|
ScopedContext context(scope, v4->currentContext());
|
|
|
|
Scoped<CallContext> ctx(scope, context->newCallContext(This, callData));
|
|
|
|
|
|
|
|
ExecutionContextSaver ctxSaver(scope, context);
|
|
|
|
ScopedValue result(scope, Q_V4_PROFILE(v4, f));
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2015-01-15 20:28:01 +00:00
|
|
|
return result->asReturnedValue();
|
2013-08-06 14:41:28 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 22:04:20 +00:00
|
|
|
void QmlBindingWrapper::markObjects(Heap::Base *m, ExecutionEngine *e)
|
2013-08-06 14:41:28 +00:00
|
|
|
{
|
2014-11-01 19:56:47 +00:00
|
|
|
QmlBindingWrapper::Data *wrapper = static_cast<QmlBindingWrapper::Data *>(m);
|
|
|
|
if (wrapper->qml)
|
|
|
|
wrapper->qml->mark(e);
|
2013-11-02 15:30:26 +00:00
|
|
|
FunctionObject::markObjects(m, e);
|
2013-08-06 14:41:28 +00:00
|
|
|
}
|
2013-05-22 12:30:57 +00:00
|
|
|
|
2014-03-31 14:49:14 +00:00
|
|
|
static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex)
|
2014-03-31 13:07:18 +00:00
|
|
|
{
|
2014-11-07 04:46:20 +00:00
|
|
|
QV4::Scope scope(ctx);
|
2015-02-14 22:22:23 +00:00
|
|
|
QV4::Scoped<CallContext> signalEmittingContext(scope, ctx->d()->parent.cast<Heap::CallContext>());
|
2014-11-07 04:46:20 +00:00
|
|
|
Q_ASSERT(signalEmittingContext && signalEmittingContext->d()->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext);
|
2014-03-31 14:49:14 +00:00
|
|
|
return signalEmittingContext->argument(parameterIndex);
|
|
|
|
}
|
|
|
|
|
2014-11-11 16:27:49 +00:00
|
|
|
Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, Function *runtimeFunction, const QList<QByteArray> &signalParameters, QString *error)
|
2014-03-31 14:49:14 +00:00
|
|
|
{
|
|
|
|
ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine);
|
2014-03-31 13:07:18 +00:00
|
|
|
QV4::Scope valueScope(engine);
|
2015-06-15 13:52:51 +00:00
|
|
|
QV4::Scoped<QmlContextWrapper> qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject));
|
2014-11-28 09:05:24 +00:00
|
|
|
ScopedContext global(valueScope, valueScope.engine->rootContext());
|
|
|
|
QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(global, qmlScopeObject));
|
2015-06-11 14:35:11 +00:00
|
|
|
QV4::Scoped<QmlContext> wrapperContext(valueScope, wrapper->context());
|
2014-03-31 14:49:14 +00:00
|
|
|
|
|
|
|
if (!signalParameters.isEmpty()) {
|
|
|
|
if (error)
|
2014-11-20 08:07:52 +00:00
|
|
|
QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error);
|
2014-03-31 14:49:14 +00:00
|
|
|
QV4::ScopedProperty p(valueScope);
|
|
|
|
QV4::ScopedString s(valueScope);
|
|
|
|
int index = 0;
|
|
|
|
foreach (const QByteArray ¶m, signalParameters) {
|
2014-11-10 15:06:43 +00:00
|
|
|
QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapperContext, index++, signalParameterGetter));
|
2014-05-08 13:32:31 +00:00
|
|
|
p->setGetter(g);
|
2014-03-31 14:49:14 +00:00
|
|
|
p->setSetter(0);
|
|
|
|
s = engine->newString(QString::fromUtf8(param));
|
2014-12-01 15:13:20 +00:00
|
|
|
qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
|
2014-03-31 14:49:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-10 15:06:43 +00:00
|
|
|
QV4::ScopedFunctionObject function(valueScope, QV4::FunctionObject::createScriptFunction(wrapperContext, runtimeFunction));
|
2014-11-11 16:27:49 +00:00
|
|
|
return function->d();
|
2014-03-31 13:07:18 +00:00
|
|
|
}
|
|
|
|
|
2014-05-07 14:14:08 +00:00
|
|
|
Script::Script(ExecutionEngine *v4, Object *qml, CompiledData::CompilationUnit *compilationUnit)
|
2015-04-28 17:18:40 +00:00
|
|
|
: line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
|
2015-01-15 10:36:57 +00:00
|
|
|
, qml(v4, qml), vmFunction(0), parseAsBinding(true)
|
2013-09-29 19:20:09 +00:00
|
|
|
{
|
|
|
|
parsed = true;
|
|
|
|
|
2014-12-14 17:33:05 +00:00
|
|
|
vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : 0;
|
|
|
|
if (vmFunction) {
|
2013-09-29 19:20:09 +00:00
|
|
|
Scope valueScope(v4);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit));
|
2015-01-13 08:01:29 +00:00
|
|
|
compilationUnitHolder.set(v4, holder);
|
2014-12-14 17:33:05 +00:00
|
|
|
}
|
2013-09-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 14:45:02 +00:00
|
|
|
Script::~Script()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-05-22 11:49:27 +00:00
|
|
|
void Script::parse()
|
|
|
|
{
|
2013-06-25 09:00:31 +00:00
|
|
|
if (parsed)
|
|
|
|
return;
|
|
|
|
|
2013-05-22 11:49:27 +00:00
|
|
|
using namespace QQmlJS;
|
|
|
|
|
2013-05-23 20:56:38 +00:00
|
|
|
parsed = true;
|
|
|
|
|
2015-04-28 17:18:40 +00:00
|
|
|
ExecutionEngine *v4 = scope->engine();
|
2013-09-13 19:54:21 +00:00
|
|
|
Scope valueScope(v4);
|
2013-05-22 12:30:57 +00:00
|
|
|
|
|
|
|
MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2014-02-14 12:58:40 +00:00
|
|
|
IR::Module module(v4->debugger != 0);
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2013-05-23 20:56:38 +00:00
|
|
|
QQmlJS::Engine ee, *engine = ⅇ
|
|
|
|
Lexer lexer(engine);
|
2013-06-02 20:56:59 +00:00
|
|
|
lexer.setCode(sourceCode, line, parseAsBinding);
|
2013-05-23 20:56:38 +00:00
|
|
|
Parser parser(engine);
|
|
|
|
|
|
|
|
const bool parsed = parser.parseProgram();
|
|
|
|
|
|
|
|
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
|
|
|
|
if (m.isError()) {
|
2014-11-28 09:05:24 +00:00
|
|
|
valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
|
2013-10-21 07:50:27 +00:00
|
|
|
return;
|
2013-05-23 20:56:38 +00:00
|
|
|
} else {
|
|
|
|
qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
|
|
|
|
<< ": warning: " << m.message;
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
2013-05-23 20:56:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (parsed) {
|
|
|
|
using namespace AST;
|
|
|
|
Program *program = AST::cast<Program *>(parser.rootNode());
|
|
|
|
if (!program) {
|
|
|
|
// if parsing was successful, and we have no program, then
|
|
|
|
// we're done...:
|
|
|
|
return;
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
2013-05-23 20:56:38 +00:00
|
|
|
|
|
|
|
QStringList inheritedLocals;
|
2014-03-05 15:24:56 +00:00
|
|
|
if (inheritContext) {
|
2014-11-28 09:05:24 +00:00
|
|
|
Scoped<CallContext> ctx(valueScope, scope);
|
2014-03-05 15:24:56 +00:00
|
|
|
if (ctx) {
|
2014-11-12 19:07:27 +00:00
|
|
|
for (Identifier * const *i = ctx->variables(), * const *ei = i + ctx->variableCount(); i < ei; ++i)
|
|
|
|
inheritedLocals.append(*i ? (*i)->string : QString());
|
2014-03-05 15:24:56 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2014-11-12 12:55:19 +00:00
|
|
|
RuntimeCodegen cg(v4, strictMode);
|
2013-10-24 12:51:02 +00:00
|
|
|
cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals);
|
2013-10-21 07:50:27 +00:00
|
|
|
if (v4->hasException)
|
|
|
|
return;
|
|
|
|
|
2013-09-01 11:11:00 +00:00
|
|
|
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
|
2013-10-30 15:49:32 +00:00
|
|
|
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
|
2013-05-23 20:56:38 +00:00
|
|
|
if (inheritContext)
|
|
|
|
isel->setUseFastLookups(false);
|
2014-10-04 15:18:15 +00:00
|
|
|
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = isel->compile();
|
2013-08-14 08:17:37 +00:00
|
|
|
vmFunction = compilationUnit->linkToEngine(v4);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit));
|
2015-01-13 08:01:29 +00:00
|
|
|
compilationUnitHolder.set(v4, holder);
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2013-09-13 19:54:21 +00:00
|
|
|
if (!vmFunction) {
|
2013-05-22 12:30:57 +00:00
|
|
|
// ### FIX file/line number
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
|
2014-07-28 08:07:57 +00:00
|
|
|
v4->throwError(error);
|
2013-09-13 19:54:21 +00:00
|
|
|
}
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-12 13:27:01 +00:00
|
|
|
ReturnedValue Script::run()
|
2013-05-22 11:49:27 +00:00
|
|
|
{
|
2013-05-23 20:56:38 +00:00
|
|
|
if (!parsed)
|
2013-05-22 12:30:57 +00:00
|
|
|
parse();
|
2013-05-23 20:56:38 +00:00
|
|
|
if (!vmFunction)
|
2013-09-12 13:27:01 +00:00
|
|
|
return Encode::undefined();
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2015-04-28 17:18:40 +00:00
|
|
|
QV4::ExecutionEngine *engine = scope->engine();
|
2013-09-11 12:47:34 +00:00
|
|
|
QV4::Scope valueScope(engine);
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2013-09-17 16:16:35 +00:00
|
|
|
if (qml.isUndefined()) {
|
2013-05-23 20:56:38 +00:00
|
|
|
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
|
2013-05-22 14:53:35 +00:00
|
|
|
|
2014-11-27 14:18:41 +00:00
|
|
|
ExecutionContextSaver ctxSaver(valueScope, scope);
|
2014-11-28 09:05:24 +00:00
|
|
|
ContextStateSaver stateSaver(valueScope, scope);
|
2015-04-28 17:18:40 +00:00
|
|
|
scope->d()->strictMode = vmFunction->isStrict();
|
|
|
|
scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups;
|
|
|
|
scope->d()->compilationUnit = vmFunction->compilationUnit;
|
2013-05-22 14:53:35 +00:00
|
|
|
|
2015-07-27 13:33:43 +00:00
|
|
|
return Q_V4_PROFILE(engine, vmFunction);
|
2013-05-22 14:53:35 +00:00
|
|
|
} else {
|
2015-06-15 13:52:51 +00:00
|
|
|
Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value());
|
2015-04-28 17:18:40 +00:00
|
|
|
ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj));
|
2014-11-28 09:19:11 +00:00
|
|
|
ScopedCallData callData(valueScope);
|
2013-09-25 10:24:36 +00:00
|
|
|
callData->thisObject = Primitive::undefinedValue();
|
2013-09-05 11:22:23 +00:00
|
|
|
return f->call(callData);
|
2013-05-22 14:53:35 +00:00
|
|
|
}
|
2013-05-22 12:30:57 +00:00
|
|
|
}
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2013-05-22 12:30:57 +00:00
|
|
|
Function *Script::function()
|
|
|
|
{
|
2013-05-23 20:56:38 +00:00
|
|
|
if (!parsed)
|
|
|
|
parse();
|
|
|
|
return vmFunction;
|
|
|
|
}
|
|
|
|
|
2014-12-05 15:32:56 +00:00
|
|
|
QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors, QQmlJS::Directives *directivesCollector)
|
2013-09-29 19:20:09 +00:00
|
|
|
{
|
|
|
|
using namespace QQmlJS;
|
|
|
|
using namespace QQmlJS::AST;
|
|
|
|
|
|
|
|
QQmlJS::Engine ee;
|
2014-12-05 15:32:56 +00:00
|
|
|
if (directivesCollector)
|
|
|
|
ee.setDirectives(directivesCollector);
|
2013-09-29 19:20:09 +00:00
|
|
|
QQmlJS::Lexer lexer(&ee);
|
2014-08-28 11:12:53 +00:00
|
|
|
lexer.setCode(source, /*line*/1, /*qml mode*/false);
|
2013-09-29 19:20:09 +00:00
|
|
|
QQmlJS::Parser parser(&ee);
|
|
|
|
|
|
|
|
parser.parseProgram();
|
|
|
|
|
|
|
|
QList<QQmlError> errors;
|
|
|
|
|
|
|
|
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
|
|
|
|
if (m.isWarning()) {
|
|
|
|
qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
QQmlError error;
|
|
|
|
error.setUrl(url);
|
|
|
|
error.setDescription(m.message);
|
|
|
|
error.setLine(m.loc.startLine);
|
|
|
|
error.setColumn(m.loc.startColumn);
|
|
|
|
errors << error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!errors.isEmpty()) {
|
|
|
|
if (reportedErrors)
|
|
|
|
*reportedErrors << errors;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Program *program = AST::cast<Program *>(parser.rootNode());
|
|
|
|
if (!program) {
|
|
|
|
// if parsing was successful, and we have no program, then
|
|
|
|
// we're done...:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-30 09:08:28 +00:00
|
|
|
QQmlJS::Codegen cg(/*strict mode*/false);
|
2014-03-18 17:21:18 +00:00
|
|
|
cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode);
|
2014-03-12 15:55:06 +00:00
|
|
|
errors = cg.qmlErrors();
|
2013-10-30 09:08:28 +00:00
|
|
|
if (!errors.isEmpty()) {
|
2013-09-29 19:20:09 +00:00
|
|
|
if (reportedErrors)
|
2014-03-12 15:55:06 +00:00
|
|
|
*reportedErrors << errors;
|
2013-09-29 19:20:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-18 17:21:18 +00:00
|
|
|
QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator));
|
2013-09-29 19:20:09 +00:00
|
|
|
isel->setUseFastLookups(false);
|
2014-03-18 17:21:18 +00:00
|
|
|
return isel->compile(/*generate unit data*/false);
|
2013-09-29 19:20:09 +00:00
|
|
|
}
|
|
|
|
|
2013-09-12 20:37:41 +00:00
|
|
|
ReturnedValue Script::qmlBinding()
|
2013-05-23 20:56:38 +00:00
|
|
|
{
|
|
|
|
if (!parsed)
|
|
|
|
parse();
|
2015-04-28 17:18:40 +00:00
|
|
|
ExecutionEngine *v4 = scope->engine();
|
2013-09-23 13:52:10 +00:00
|
|
|
Scope valueScope(v4);
|
2015-06-15 13:52:51 +00:00
|
|
|
Scoped<QmlContextWrapper> qmlObj(valueScope, qml.value());
|
2015-04-28 17:18:40 +00:00
|
|
|
ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj));
|
2013-09-25 13:24:50 +00:00
|
|
|
return v.asReturnedValue();
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
|
|
|
|
2015-08-12 10:15:47 +00:00
|
|
|
QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject)
|
2013-05-22 14:26:45 +00:00
|
|
|
{
|
2013-09-12 13:27:01 +00:00
|
|
|
QV4::Scope scope(engine);
|
2013-05-22 14:26:45 +00:00
|
|
|
QV4::Script qmlScript(engine, scopeObject, script, QString());
|
|
|
|
|
2013-10-21 07:50:27 +00:00
|
|
|
qmlScript.parse();
|
|
|
|
QV4::ScopedValue result(scope);
|
|
|
|
if (!scope.engine->hasException)
|
|
|
|
result = qmlScript.run();
|
|
|
|
if (scope.engine->hasException) {
|
2014-11-12 12:55:55 +00:00
|
|
|
scope.engine->catchException();
|
2013-10-21 07:50:27 +00:00
|
|
|
return Encode::undefined();
|
2013-05-22 14:26:45 +00:00
|
|
|
}
|
2015-01-15 20:28:01 +00:00
|
|
|
return result->asReturnedValue();
|
2013-05-22 14:26:45 +00:00
|
|
|
}
|