2012-10-12 08:12:24 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
|
|
** Contact: http://www.qt-project.org/legal
|
|
|
|
**
|
|
|
|
** This file is part of the V4VM 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$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
2012-04-16 19:23:25 +00:00
|
|
|
|
2013-04-15 09:50:16 +00:00
|
|
|
#include "private/qv4object_p.h"
|
|
|
|
#include "private/qv4runtime_p.h"
|
|
|
|
#include "private/qv4functionobject_p.h"
|
|
|
|
#include "private/qv4errorobject_p.h"
|
|
|
|
#include "private/qv4globalobject_p.h"
|
2013-01-29 13:20:50 +00:00
|
|
|
#include "private/qv4codegen_p.h"
|
|
|
|
#include "private/qv4isel_moth_p.h"
|
|
|
|
#include "private/qv4vme_moth_p.h"
|
2013-04-15 09:50:16 +00:00
|
|
|
#include "private/qv4objectproto_p.h"
|
2013-01-29 13:20:50 +00:00
|
|
|
#include "private/qv4isel_p.h"
|
2013-04-15 09:50:16 +00:00
|
|
|
#include "private/qv4mm_p.h"
|
|
|
|
#include "private/qv4context_p.h"
|
2013-05-22 14:53:35 +00:00
|
|
|
#include "private/qv4script_p.h"
|
2013-07-10 13:44:11 +00:00
|
|
|
#include "private/qv4exception_p.h"
|
2012-04-16 19:23:25 +00:00
|
|
|
|
2013-05-07 09:54:45 +00:00
|
|
|
#ifdef V4_ENABLE_JIT
|
|
|
|
# include "private/qv4isel_masm_p.h"
|
|
|
|
#endif // V4_ENABLE_JIT
|
|
|
|
|
2012-04-16 19:23:25 +00:00
|
|
|
#include <QtCore>
|
|
|
|
#include <private/qqmljsengine_p.h>
|
|
|
|
#include <private/qqmljslexer_p.h>
|
|
|
|
#include <private/qqmljsparser_p.h>
|
|
|
|
#include <private/qqmljsast_p.h>
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
2012-05-07 14:05:05 +00:00
|
|
|
namespace builtins {
|
2012-05-09 09:04:57 +00:00
|
|
|
|
2013-04-19 13:37:33 +00:00
|
|
|
using namespace QV4;
|
2012-05-09 09:04:57 +00:00
|
|
|
|
2013-02-07 15:14:44 +00:00
|
|
|
struct Print: FunctionObject
|
2012-05-07 14:05:05 +00:00
|
|
|
{
|
2012-11-29 13:39:19 +00:00
|
|
|
Print(ExecutionContext *scope): FunctionObject(scope) {
|
2013-02-14 13:07:57 +00:00
|
|
|
vtbl = &static_vtbl;
|
2012-11-29 13:39:19 +00:00
|
|
|
name = scope->engine->newString("print");
|
|
|
|
}
|
2012-05-13 11:50:55 +00:00
|
|
|
|
2013-09-11 11:55:01 +00:00
|
|
|
static ReturnedValue call(Managed *, CallData *callData)
|
2012-05-07 14:05:05 +00:00
|
|
|
{
|
2013-09-06 10:44:12 +00:00
|
|
|
for (int i = 0; i < callData->argc; ++i) {
|
2013-09-09 12:33:28 +00:00
|
|
|
QString s = callData->args[i].toQStringNoThrow();
|
2012-05-07 14:05:05 +00:00
|
|
|
if (i)
|
|
|
|
std::cout << ' ';
|
2013-06-22 08:02:06 +00:00
|
|
|
std::cout << qPrintable(s);
|
2012-05-07 14:05:05 +00:00
|
|
|
}
|
|
|
|
std::cout << std::endl;
|
2013-09-11 11:55:01 +00:00
|
|
|
return Value::undefinedValue().asReturnedValue();
|
2012-05-07 14:05:05 +00:00
|
|
|
}
|
2013-02-14 13:07:57 +00:00
|
|
|
|
|
|
|
static const ManagedVTable static_vtbl;
|
2012-05-07 14:05:05 +00:00
|
|
|
};
|
2012-05-09 09:04:57 +00:00
|
|
|
|
2013-02-14 13:07:57 +00:00
|
|
|
DEFINE_MANAGED_VTABLE(Print);
|
|
|
|
|
2013-02-07 15:14:44 +00:00
|
|
|
struct GC: public FunctionObject
|
2012-12-08 17:20:54 +00:00
|
|
|
{
|
|
|
|
GC(ExecutionContext* scope)
|
|
|
|
: FunctionObject(scope)
|
|
|
|
{
|
2013-02-14 13:07:57 +00:00
|
|
|
vtbl = &static_vtbl;
|
2012-12-08 17:20:54 +00:00
|
|
|
name = scope->engine->newString("gc");
|
|
|
|
}
|
2013-09-11 11:55:01 +00:00
|
|
|
static ReturnedValue call(Managed *m, CallData *)
|
2012-12-08 17:20:54 +00:00
|
|
|
{
|
2013-06-22 08:02:06 +00:00
|
|
|
m->engine()->memoryManager->runGC();
|
2013-09-11 11:55:01 +00:00
|
|
|
return Value::undefinedValue().asReturnedValue();
|
2012-12-08 17:20:54 +00:00
|
|
|
}
|
2013-02-14 13:07:57 +00:00
|
|
|
|
|
|
|
static const ManagedVTable static_vtbl;
|
2012-12-08 17:20:54 +00:00
|
|
|
};
|
|
|
|
|
2013-02-14 13:07:57 +00:00
|
|
|
DEFINE_MANAGED_VTABLE(GC);
|
|
|
|
|
2012-05-07 14:05:05 +00:00
|
|
|
} // builtins
|
|
|
|
|
2013-05-25 13:31:23 +00:00
|
|
|
static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exception)
|
2012-11-20 08:47:18 +00:00
|
|
|
{
|
2013-09-12 13:27:01 +00:00
|
|
|
QV4::Scope scope(ctx);
|
|
|
|
QV4::ScopedValue ex(scope, exception.value());
|
|
|
|
QV4::ErrorObject *e = ex->asErrorObject();
|
2012-11-28 10:00:23 +00:00
|
|
|
if (!e) {
|
2013-09-12 13:27:01 +00:00
|
|
|
std::cerr << "Uncaught exception: " << qPrintable(ex->toString(ctx)->toQString()) << std::endl;
|
2013-05-25 13:31:23 +00:00
|
|
|
} else {
|
2013-09-18 13:34:13 +00:00
|
|
|
QV4::ScopedString m(scope, ctx->engine->newString(QStringLiteral("message")));
|
|
|
|
QV4::ScopedValue message(scope, e->get(m));
|
|
|
|
std::cerr << "Uncaught exception: " << qPrintable(message->toQStringNoThrow()) << std::endl;
|
2013-05-25 13:31:23 +00:00
|
|
|
}
|
2012-11-28 10:00:23 +00:00
|
|
|
|
2013-05-25 13:31:23 +00:00
|
|
|
foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) {
|
2013-05-27 12:19:35 +00:00
|
|
|
std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source);
|
2013-05-25 13:31:23 +00:00
|
|
|
if (frame.line >= 0)
|
|
|
|
std::cerr << ":" << frame.line;
|
|
|
|
std::cerr << ")" << std::endl;
|
2012-11-28 10:00:23 +00:00
|
|
|
}
|
2012-11-20 08:47:18 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 19:23:25 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
QCoreApplication app(argc, argv);
|
|
|
|
QStringList args = app.arguments();
|
|
|
|
args.removeFirst();
|
|
|
|
|
2012-11-08 11:45:40 +00:00
|
|
|
enum {
|
|
|
|
use_masm,
|
2013-08-08 06:58:48 +00:00
|
|
|
use_moth
|
2013-06-25 14:07:41 +00:00
|
|
|
} mode;
|
|
|
|
#ifdef V4_ENABLE_JIT
|
|
|
|
mode = use_masm;
|
|
|
|
#else
|
|
|
|
mode = use_moth;
|
|
|
|
#endif
|
2012-11-08 11:45:40 +00:00
|
|
|
|
2013-06-17 11:36:21 +00:00
|
|
|
bool runAsQml = false;
|
2012-11-29 13:41:26 +00:00
|
|
|
|
2012-11-08 11:45:40 +00:00
|
|
|
if (!args.isEmpty()) {
|
|
|
|
if (args.first() == QLatin1String("--jit")) {
|
|
|
|
mode = use_masm;
|
|
|
|
args.removeFirst();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args.first() == QLatin1String("--interpret")) {
|
|
|
|
mode = use_moth;
|
|
|
|
args.removeFirst();
|
|
|
|
}
|
|
|
|
|
2013-06-17 11:36:21 +00:00
|
|
|
if (args.first() == QLatin1String("--qml")) {
|
|
|
|
runAsQml = true;
|
|
|
|
args.removeFirst();
|
|
|
|
}
|
|
|
|
|
2012-11-08 11:45:40 +00:00
|
|
|
if (args.first() == QLatin1String("--help")) {
|
2012-11-29 13:41:26 +00:00
|
|
|
std::cerr << "Usage: v4 [|--debug|-d] [|--jit|--interpret|--compile|--aot|--llvm-jit] file..." << std::endl;
|
2012-11-08 11:45:40 +00:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
2012-06-05 16:32:52 +00:00
|
|
|
}
|
|
|
|
|
2012-11-08 11:45:40 +00:00
|
|
|
switch (mode) {
|
|
|
|
case use_masm:
|
|
|
|
case use_moth: {
|
2013-03-05 15:11:22 +00:00
|
|
|
QQmlJS::EvalISelFactory* iSelFactory = 0;
|
2012-12-04 12:40:18 +00:00
|
|
|
if (mode == use_moth) {
|
2013-03-05 15:11:22 +00:00
|
|
|
iSelFactory = new QQmlJS::Moth::ISelFactory;
|
2013-05-07 09:54:45 +00:00
|
|
|
#ifdef V4_ENABLE_JIT
|
2012-12-04 12:40:18 +00:00
|
|
|
} else {
|
2013-03-05 15:11:22 +00:00
|
|
|
iSelFactory = new QQmlJS::MASM::ISelFactory;
|
2013-05-07 09:54:45 +00:00
|
|
|
#endif // V4_ENABLE_JIT
|
2012-12-04 12:40:18 +00:00
|
|
|
}
|
2012-11-29 13:41:26 +00:00
|
|
|
|
2013-04-19 13:37:33 +00:00
|
|
|
QV4::ExecutionEngine vm(iSelFactory);
|
2012-11-29 13:41:26 +00:00
|
|
|
|
2013-04-19 13:37:33 +00:00
|
|
|
QV4::ExecutionContext *ctx = vm.rootContext;
|
2013-09-12 13:27:01 +00:00
|
|
|
QV4::Scope scope(ctx);
|
2012-06-05 16:32:52 +00:00
|
|
|
|
2013-09-18 14:36:02 +00:00
|
|
|
QV4::ScopedObject globalObject(scope, vm.globalObject);
|
|
|
|
QV4::ScopedObject print(scope, new (ctx->engine->memoryManager) builtins::Print(ctx));
|
|
|
|
globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("print"))), print);
|
|
|
|
QV4::ScopedObject gc(scope, new (ctx->engine->memoryManager) builtins::GC(ctx));
|
|
|
|
globalObject->put(QV4::ScopedString(scope, vm.newIdentifier(QStringLiteral("gc"))), gc);
|
2012-11-08 11:45:40 +00:00
|
|
|
|
|
|
|
foreach (const QString &fn, args) {
|
|
|
|
QFile file(fn);
|
|
|
|
if (file.open(QFile::ReadOnly)) {
|
|
|
|
const QString code = QString::fromUtf8(file.readAll());
|
|
|
|
file.close();
|
|
|
|
|
Implement JavaScript exceptions using C++ exceptions
Instead of registering catch handlers with setjmp and throwing JS exceptions
with longjmp, they are now thrown and caught as C++ exceptions. This allows for
tight interoperability between C++ and JS in the future and allows for clear
semantics with regards to cleaning up memory in the engine when throwing
exceptions. (destructors are guaranteed to be called, unlike with
setjmp/longjmp).
The recent unwind table additions allow for the exceptions to be thrown through
JIT generated code.
Catching the exception is done by re-using the existing IR semantics where the
beginning of a try block is marked by registering an exception handler.
Execution after the registration continues conditionally, based on the return
value of builtin_create_exception_handler. A return value of is 0 the try
block(s) are executed. If an exception is thrown during that time, execution
resumes at the point where builtin_create_exception_handler returns, but with a
return value of 1. If an exception is thrown within the catch handler, the
execution resumes again at the same point, but the inCatch IR variable will
guide execution straight to the finally block(s), which calls
delete_exception_handler.
In the JIT as well as the interpreter this is implemented by entering a C++
code section that contains a C++ try {} catch {} block, in which the calling
function is called again and continues right at the next instruction (or the
interpreter loop is recursively entered). An exception will throw us out of
that scope and back into the try {} catch {} wrapper, which can call again
into the calling function.
The IR guarantees that delete_exception_handler is always called, regardless of
how the try or catch blocks are terminated. That is where in the JIT and
interpreter we return from the nested function call and return back into the
original stack frame, effectively unregistering the catch handler.
Further cleanups with regards to the naming and the exception handler stack
will come in subsequent patches, this is merely the minimal patch set to
change to the new mechanism.
This patch set breaks ARM until ARM exception handler tables are implemented.
The interpreter changes are based on a patchset from Erik
from https://codereview.qt-project.org/#change,45750
Change-Id: I543f2bd37b2186f7e48ffcab177d57b5ce932a0c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2013-03-01 16:04:21 +00:00
|
|
|
try {
|
2013-05-22 14:53:35 +00:00
|
|
|
QV4::Script script(ctx, code, fn);
|
2013-06-17 11:36:21 +00:00
|
|
|
script.parseAsBinding = runAsQml;
|
2013-05-22 14:53:35 +00:00
|
|
|
script.parse();
|
2013-09-12 13:27:01 +00:00
|
|
|
QV4::ScopedValue result(scope, script.run());
|
|
|
|
if (!result->isUndefined()) {
|
Implement JavaScript exceptions using C++ exceptions
Instead of registering catch handlers with setjmp and throwing JS exceptions
with longjmp, they are now thrown and caught as C++ exceptions. This allows for
tight interoperability between C++ and JS in the future and allows for clear
semantics with regards to cleaning up memory in the engine when throwing
exceptions. (destructors are guaranteed to be called, unlike with
setjmp/longjmp).
The recent unwind table additions allow for the exceptions to be thrown through
JIT generated code.
Catching the exception is done by re-using the existing IR semantics where the
beginning of a try block is marked by registering an exception handler.
Execution after the registration continues conditionally, based on the return
value of builtin_create_exception_handler. A return value of is 0 the try
block(s) are executed. If an exception is thrown during that time, execution
resumes at the point where builtin_create_exception_handler returns, but with a
return value of 1. If an exception is thrown within the catch handler, the
execution resumes again at the same point, but the inCatch IR variable will
guide execution straight to the finally block(s), which calls
delete_exception_handler.
In the JIT as well as the interpreter this is implemented by entering a C++
code section that contains a C++ try {} catch {} block, in which the calling
function is called again and continues right at the next instruction (or the
interpreter loop is recursively entered). An exception will throw us out of
that scope and back into the try {} catch {} wrapper, which can call again
into the calling function.
The IR guarantees that delete_exception_handler is always called, regardless of
how the try or catch blocks are terminated. That is where in the JIT and
interpreter we return from the nested function call and return back into the
original stack frame, effectively unregistering the catch handler.
Further cleanups with regards to the naming and the exception handler stack
will come in subsequent patches, this is merely the minimal patch set to
change to the new mechanism.
This patch set breaks ARM until ARM exception handler tables are implemented.
The interpreter changes are based on a patchset from Erik
from https://codereview.qt-project.org/#change,45750
Change-Id: I543f2bd37b2186f7e48ffcab177d57b5ce932a0c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2013-03-01 16:04:21 +00:00
|
|
|
if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
|
2013-09-12 13:27:01 +00:00
|
|
|
std::cout << "exit value: " << qPrintable(result->toString(ctx)->toQString()) << std::endl;
|
Implement JavaScript exceptions using C++ exceptions
Instead of registering catch handlers with setjmp and throwing JS exceptions
with longjmp, they are now thrown and caught as C++ exceptions. This allows for
tight interoperability between C++ and JS in the future and allows for clear
semantics with regards to cleaning up memory in the engine when throwing
exceptions. (destructors are guaranteed to be called, unlike with
setjmp/longjmp).
The recent unwind table additions allow for the exceptions to be thrown through
JIT generated code.
Catching the exception is done by re-using the existing IR semantics where the
beginning of a try block is marked by registering an exception handler.
Execution after the registration continues conditionally, based on the return
value of builtin_create_exception_handler. A return value of is 0 the try
block(s) are executed. If an exception is thrown during that time, execution
resumes at the point where builtin_create_exception_handler returns, but with a
return value of 1. If an exception is thrown within the catch handler, the
execution resumes again at the same point, but the inCatch IR variable will
guide execution straight to the finally block(s), which calls
delete_exception_handler.
In the JIT as well as the interpreter this is implemented by entering a C++
code section that contains a C++ try {} catch {} block, in which the calling
function is called again and continues right at the next instruction (or the
interpreter loop is recursively entered). An exception will throw us out of
that scope and back into the try {} catch {} wrapper, which can call again
into the calling function.
The IR guarantees that delete_exception_handler is always called, regardless of
how the try or catch blocks are terminated. That is where in the JIT and
interpreter we return from the nested function call and return back into the
original stack frame, effectively unregistering the catch handler.
Further cleanups with regards to the naming and the exception handler stack
will come in subsequent patches, this is merely the minimal patch set to
change to the new mechanism.
This patch set breaks ARM until ARM exception handler tables are implemented.
The interpreter changes are based on a patchset from Erik
from https://codereview.qt-project.org/#change,45750
Change-Id: I543f2bd37b2186f7e48ffcab177d57b5ce932a0c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2013-03-01 16:04:21 +00:00
|
|
|
}
|
2013-04-19 13:37:33 +00:00
|
|
|
} catch (QV4::Exception& ex) {
|
2013-03-04 11:12:21 +00:00
|
|
|
ex.accept(ctx);
|
2013-05-25 13:31:23 +00:00
|
|
|
showException(ctx, ex);
|
2012-11-18 23:00:50 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-11-13 12:44:16 +00:00
|
|
|
} else {
|
|
|
|
std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
|
|
|
|
return EXIT_FAILURE;
|
2012-11-08 11:45:40 +00:00
|
|
|
}
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|
2012-12-04 12:40:18 +00:00
|
|
|
|
2013-01-03 11:26:19 +00:00
|
|
|
vm.memoryManager->dumpStats();
|
2012-11-08 11:45:40 +00:00
|
|
|
} return EXIT_SUCCESS;
|
2013-01-23 09:12:51 +00:00
|
|
|
} // switch (mode)
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|