2013-05-22 11:49:27 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2013-06-24 11:50:51 +00:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2013-05-22 11:49:27 +00:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
|
|
|
**
|
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
|
|
|
**
|
|
|
|
** $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 "qv4script_p.h"
|
|
|
|
#include "qv4mm_p.h"
|
|
|
|
#include "qv4functionobject_p.h"
|
|
|
|
#include "qv4function_p.h"
|
|
|
|
#include "qv4context_p.h"
|
|
|
|
#include "qv4debugging_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>
|
|
|
|
#include <qv4jsir_p.h>
|
|
|
|
#include <qv4codegen_p.h>
|
|
|
|
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/QString>
|
|
|
|
|
|
|
|
using namespace QV4;
|
|
|
|
|
2013-09-27 15:04:42 +00:00
|
|
|
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
|
2013-08-06 14:41:28 +00:00
|
|
|
: FunctionObject(scope, scope->engine->id_eval)
|
|
|
|
, qml(qml)
|
2013-05-22 12:30:57 +00:00
|
|
|
{
|
2013-08-06 14:41:28 +00:00
|
|
|
vtbl = &static_vtbl;
|
|
|
|
function = f;
|
|
|
|
function->compilationUnit->ref();
|
|
|
|
needsActivation = function->needsActivation();
|
2013-09-25 10:24:36 +00:00
|
|
|
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
|
2013-08-06 14:41:28 +00:00
|
|
|
|
|
|
|
qmlContext = scope->engine->current->newQmlContext(this, qml);
|
|
|
|
scope->engine->popContext();
|
|
|
|
}
|
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
|
|
|
|
2013-09-27 15:04:42 +00:00
|
|
|
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
|
2013-09-13 11:43:15 +00:00
|
|
|
: FunctionObject(scope, scope->engine->id_eval)
|
|
|
|
, qml(qml)
|
|
|
|
{
|
|
|
|
vtbl = &static_vtbl;
|
|
|
|
function = 0;
|
|
|
|
needsActivation = false;
|
2013-09-25 10:24:36 +00:00
|
|
|
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
|
2013-09-13 11:43:15 +00:00
|
|
|
|
|
|
|
qmlContext = scope->engine->current->newQmlContext(this, qml);
|
|
|
|
scope->engine->popContext();
|
|
|
|
}
|
|
|
|
|
2013-09-20 06:21:42 +00:00
|
|
|
ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
|
2013-08-06 14:41:28 +00:00
|
|
|
{
|
|
|
|
ExecutionEngine *engine = that->engine();
|
2013-09-20 06:21:42 +00:00
|
|
|
Scope scope(engine);
|
2013-08-06 14:41:28 +00:00
|
|
|
QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
|
2013-09-13 11:43:15 +00:00
|
|
|
Q_ASSERT(This->function);
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2013-08-06 14:41:28 +00:00
|
|
|
CallContext *ctx = This->qmlContext;
|
2013-09-25 10:24:36 +00:00
|
|
|
std::fill(ctx->locals, ctx->locals + ctx->function->varCount, Primitive::undefinedValue());
|
2013-08-06 14:41:28 +00:00
|
|
|
engine->pushContext(ctx);
|
2013-09-20 06:21:42 +00:00
|
|
|
ScopedValue result(scope, This->function->code(ctx, This->function->codeData));
|
2013-08-06 14:41:28 +00:00
|
|
|
engine->popContext();
|
2013-05-23 20:56:38 +00:00
|
|
|
|
2013-09-20 06:21:42 +00:00
|
|
|
return result.asReturnedValue();
|
2013-08-06 14:41:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QmlBindingWrapper::markObjects(Managed *m)
|
|
|
|
{
|
|
|
|
QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
|
|
|
|
if (wrapper->qml)
|
|
|
|
wrapper->qml->mark();
|
|
|
|
FunctionObject::markObjects(m);
|
|
|
|
wrapper->qmlContext->mark();
|
|
|
|
}
|
2013-05-22 12:30:57 +00:00
|
|
|
|
2013-05-23 20:56:38 +00:00
|
|
|
DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
|
|
|
|
|
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
|
|
|
struct CompilationUnitHolder : public QV4::Object
|
|
|
|
{
|
|
|
|
Q_MANAGED
|
|
|
|
|
|
|
|
CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit)
|
|
|
|
: Object(engine)
|
|
|
|
, unit(unit)
|
|
|
|
{
|
|
|
|
unit->ref();
|
|
|
|
vtbl = &static_vtbl;
|
|
|
|
}
|
|
|
|
~CompilationUnitHolder()
|
|
|
|
{
|
|
|
|
unit->deref();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy(Managed *that)
|
|
|
|
{
|
|
|
|
static_cast<CompilationUnitHolder*>(that)->~CompilationUnitHolder();
|
|
|
|
}
|
|
|
|
|
|
|
|
QV4::CompiledData::CompilationUnit *unit;
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_MANAGED_VTABLE(CompilationUnitHolder);
|
|
|
|
|
2013-09-29 19:20:09 +00:00
|
|
|
Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit)
|
|
|
|
: line(0), column(0), scope(v4->rootContext), strictMode(false), inheritContext(true), parsed(false)
|
|
|
|
, qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true)
|
|
|
|
{
|
|
|
|
parsed = true;
|
|
|
|
|
|
|
|
if (compilationUnit) {
|
|
|
|
vmFunction = compilationUnit->linkToEngine(v4);
|
|
|
|
Q_ASSERT(vmFunction);
|
|
|
|
Scope valueScope(v4);
|
2013-09-30 20:41:12 +00:00
|
|
|
ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
|
2013-09-29 19:20:09 +00:00
|
|
|
compilationUnitHolder = holder;
|
|
|
|
} else
|
|
|
|
vmFunction = 0;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2013-05-22 12:30:57 +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
|
|
|
|
|
|
|
V4IR::Module module;
|
|
|
|
|
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()) {
|
2013-08-08 14:59:32 +00:00
|
|
|
scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
|
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;
|
|
|
|
if (inheritContext)
|
|
|
|
for (String * const *i = scope->variables(), * const *ei = i + scope->variableCount(); i < ei; ++i)
|
|
|
|
inheritedLocals.append(*i ? (*i)->toQString() : QString());
|
|
|
|
|
2013-08-08 14:59:32 +00:00
|
|
|
RuntimeCodegen cg(scope, strictMode);
|
2013-08-06 12:18:57 +00:00
|
|
|
cg.generateFromProgram(sourceFile, sourceCode, program, &module,
|
|
|
|
parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
|
2013-09-01 11:11:00 +00:00
|
|
|
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
|
|
|
|
QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
|
2013-05-23 20:56:38 +00:00
|
|
|
if (inheritContext)
|
|
|
|
isel->setUseFastLookups(false);
|
2013-08-14 08:17:37 +00:00
|
|
|
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
|
|
|
|
vmFunction = compilationUnit->linkToEngine(v4);
|
2013-09-26 20:07:27 +00:00
|
|
|
ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
|
2013-09-23 13:52:10 +00:00
|
|
|
compilationUnitHolder = 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
|
2013-09-13 19:54:21 +00:00
|
|
|
Scoped<Object> error(valueScope, v4->newSyntaxErrorObject("Syntax error"));
|
|
|
|
v4->current->throwError(error);
|
|
|
|
}
|
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
|
|
|
|
2013-05-22 12:30:57 +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
|
|
|
|
|
|
|
bool strict = scope->strictMode;
|
2013-08-15 08:36:41 +00:00
|
|
|
Lookup *oldLookups = scope->lookups;
|
2013-08-17 10:08:21 +00:00
|
|
|
CompiledData::CompilationUnit * const oldCompilationUnit = scope->compilationUnit;
|
2013-05-22 14:53:35 +00:00
|
|
|
|
2013-08-14 13:58:54 +00:00
|
|
|
scope->strictMode = vmFunction->isStrict();
|
2013-08-15 10:48:05 +00:00
|
|
|
scope->lookups = vmFunction->compilationUnit->runtimeLookups;
|
2013-08-17 10:08:21 +00:00
|
|
|
scope->compilationUnit = vmFunction->compilationUnit;
|
2013-05-22 14:53:35 +00:00
|
|
|
|
2013-09-11 10:46:20 +00:00
|
|
|
QV4::ScopedValue result(valueScope);
|
2013-05-22 14:53:35 +00:00
|
|
|
try {
|
2013-05-23 20:56:38 +00:00
|
|
|
result = vmFunction->code(scope, vmFunction->codeData);
|
2013-09-11 11:23:21 +00:00
|
|
|
} catch (...) {
|
2013-05-22 14:53:35 +00:00
|
|
|
scope->strictMode = strict;
|
2013-08-15 08:36:41 +00:00
|
|
|
scope->lookups = oldLookups;
|
2013-08-17 10:08:21 +00:00
|
|
|
scope->compilationUnit = oldCompilationUnit;
|
2013-09-11 11:23:21 +00:00
|
|
|
scope->rethrowException();
|
2013-05-22 14:53:35 +00:00
|
|
|
}
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2013-08-17 10:08:21 +00:00
|
|
|
scope->lookups = oldLookups;
|
|
|
|
scope->compilationUnit = oldCompilationUnit;
|
|
|
|
|
2013-09-12 13:27:01 +00:00
|
|
|
return result.asReturnedValue();
|
2013-05-22 11:49:27 +00:00
|
|
|
|
2013-05-22 14:53:35 +00:00
|
|
|
} else {
|
2013-09-23 13:52:10 +00:00
|
|
|
ScopedObject qmlObj(valueScope, qml.value());
|
2013-09-27 15:04:42 +00:00
|
|
|
FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj);
|
2013-09-11 12:36:01 +00:00
|
|
|
ScopedCallData callData(valueScope, 0);
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-29 19:20:09 +00:00
|
|
|
struct PrecompilingCodeGen : public QQmlJS::Codegen
|
|
|
|
{
|
|
|
|
struct CompileError {};
|
|
|
|
|
|
|
|
PrecompilingCodeGen(bool strict)
|
|
|
|
: QQmlJS::Codegen(strict)
|
|
|
|
{}
|
|
|
|
|
|
|
|
virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail)
|
|
|
|
{
|
|
|
|
QQmlJS::Codegen::throwSyntaxError(loc, detail);
|
|
|
|
throw CompileError();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail)
|
|
|
|
{
|
|
|
|
QQmlJS::Codegen::throwReferenceError(loc, detail);
|
|
|
|
throw CompileError();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, bool parseAsBinding, QList<QQmlError> *reportedErrors)
|
|
|
|
{
|
|
|
|
using namespace QQmlJS;
|
|
|
|
using namespace QQmlJS::AST;
|
|
|
|
|
|
|
|
QQmlJS::V4IR::Module module;
|
|
|
|
|
|
|
|
QQmlJS::Engine ee;
|
|
|
|
QQmlJS::Lexer lexer(&ee);
|
|
|
|
lexer.setCode(source, /*line*/1, /*qml mode*/true);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrecompilingCodeGen cg(/*strict mode*/false);
|
|
|
|
try {
|
|
|
|
cg.generateFromProgram(url.toString(), source, program, &module, parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::GlobalCode);
|
|
|
|
} catch (const PrecompilingCodeGen::CompileError &) {
|
|
|
|
if (reportedErrors)
|
|
|
|
*reportedErrors << cg.errors();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Compiler::JSUnitGenerator jsGenerator(&module);
|
|
|
|
QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(engine->executableAllocator, &module, &jsGenerator));
|
|
|
|
isel->setUseFastLookups(false);
|
|
|
|
return isel->compile();
|
|
|
|
}
|
|
|
|
|
2013-09-12 20:37:41 +00:00
|
|
|
ReturnedValue Script::qmlBinding()
|
2013-05-23 20:56:38 +00:00
|
|
|
{
|
|
|
|
if (!parsed)
|
|
|
|
parse();
|
2013-09-23 13:52:10 +00:00
|
|
|
ExecutionEngine *v4 = scope->engine;
|
|
|
|
Scope valueScope(v4);
|
|
|
|
ScopedObject qmlObj(valueScope, qml.value());
|
2013-09-27 15:04:42 +00:00
|
|
|
ScopedObject v(valueScope, new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj));
|
2013-09-25 13:24:50 +00:00
|
|
|
return v.asReturnedValue();
|
2013-05-22 11:49:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-23 13:52:10 +00:00
|
|
|
QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, ObjectRef 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());
|
|
|
|
|
|
|
|
QV4::ExecutionContext *ctx = engine->current;
|
|
|
|
try {
|
|
|
|
qmlScript.parse();
|
2013-09-12 13:27:01 +00:00
|
|
|
return qmlScript.run();
|
2013-09-11 11:23:21 +00:00
|
|
|
} catch (...) {
|
|
|
|
ctx->catchException();
|
2013-05-22 14:26:45 +00:00
|
|
|
}
|
2013-09-12 13:27:01 +00:00
|
|
|
return Encode::undefined();
|
2013-05-22 14:26:45 +00:00
|
|
|
}
|