Move the engine and context classes into their own files

Change-Id: Ie20138990908a921ca3d7475618275ed82d9cb5c
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2012-11-17 21:54:26 +01:00 committed by Simon Hausmann
parent d7416a80fa
commit 65724ce3e7
10 changed files with 807 additions and 559 deletions

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include "qmljs_runtime.h"
#include "qmljs_environment.h"
#include <stdio.h>
#include <setjmp.h>

339
qmljs_engine.cpp Normal file
View File

@ -0,0 +1,339 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include <qmljs_engine.h>
#include <qmljs_objects.h>
#include <qv4ecmaobjects_p.h>
namespace QQmlJS {
namespace VM {
ExecutionEngine::ExecutionEngine()
{
rootContext = newContext();
rootContext->init(this);
id_length = identifier(QStringLiteral("length"));
id_prototype = identifier(QStringLiteral("prototype"));
id_constructor = identifier(QStringLiteral("constructor"));
id_arguments = identifier(QStringLiteral("arguments"));
id___proto__ = identifier(QStringLiteral("__proto__"));
objectPrototype = new ObjectPrototype();
stringPrototype = new StringPrototype(rootContext);
numberPrototype = new NumberPrototype();
booleanPrototype = new BooleanPrototype();
arrayPrototype = new ArrayPrototype();
datePrototype = new DatePrototype();
functionPrototype = new FunctionPrototype(rootContext);
regExpPrototype = new RegExpPrototype();
errorPrototype = new ErrorPrototype();
evalErrorPrototype = new EvalErrorPrototype(rootContext);
rangeErrorPrototype = new RangeErrorPrototype(rootContext);
referenceErrorPrototype = new ReferenceErrorPrototype(rootContext);
syntaxErrorPrototype = new SyntaxErrorPrototype(rootContext);
typeErrorPrototype = new TypeErrorPrototype(rootContext);
uRIErrorPrototype = new URIErrorPrototype(rootContext);
stringPrototype->prototype = objectPrototype;
numberPrototype->prototype = objectPrototype;
booleanPrototype->prototype = objectPrototype;
arrayPrototype->prototype = objectPrototype;
datePrototype->prototype = objectPrototype;
functionPrototype->prototype = objectPrototype;
regExpPrototype->prototype = objectPrototype;
errorPrototype->prototype = objectPrototype;
evalErrorPrototype->prototype = errorPrototype;
rangeErrorPrototype->prototype = errorPrototype;
referenceErrorPrototype->prototype = errorPrototype;
syntaxErrorPrototype->prototype = errorPrototype;
typeErrorPrototype->prototype = errorPrototype;
uRIErrorPrototype->prototype = errorPrototype;
objectCtor = Value::fromObject(new ObjectCtor(rootContext));
stringCtor = Value::fromObject(new StringCtor(rootContext));
numberCtor = Value::fromObject(new NumberCtor(rootContext));
booleanCtor = Value::fromObject(new BooleanCtor(rootContext));
arrayCtor = Value::fromObject(new ArrayCtor(rootContext));
functionCtor = Value::fromObject(new FunctionCtor(rootContext));
dateCtor = Value::fromObject(new DateCtor(rootContext));
regExpCtor = Value::fromObject(new RegExpCtor(rootContext));
errorCtor = Value::fromObject(new ErrorCtor(rootContext));
evalErrorCtor = Value::fromObject(new EvalErrorCtor(rootContext));
rangeErrorCtor = Value::fromObject(new RangeErrorCtor(rootContext));
referenceErrorCtor = Value::fromObject(new ReferenceErrorCtor(rootContext));
syntaxErrorCtor = Value::fromObject(new SyntaxErrorCtor(rootContext));
typeErrorCtor = Value::fromObject(new TypeErrorCtor(rootContext));
uRIErrorCtor = Value::fromObject(new URIErrorCtor(rootContext));
stringCtor.objectValue()->prototype = functionPrototype;
numberCtor.objectValue()->prototype = functionPrototype;
booleanCtor.objectValue()->prototype = functionPrototype;
arrayCtor.objectValue()->prototype = functionPrototype;
functionCtor.objectValue()->prototype = functionPrototype;
dateCtor.objectValue()->prototype = functionPrototype;
regExpCtor.objectValue()->prototype = functionPrototype;
errorCtor.objectValue()->prototype = functionPrototype;
evalErrorCtor.objectValue()->prototype = errorPrototype;
rangeErrorCtor.objectValue()->prototype = errorPrototype;
referenceErrorCtor.objectValue()->prototype = errorPrototype;
syntaxErrorCtor.objectValue()->prototype = errorPrototype;
typeErrorCtor.objectValue()->prototype = errorPrototype;
uRIErrorCtor.objectValue()->prototype = errorPrototype;
objectPrototype->init(rootContext, objectCtor);
stringPrototype->init(rootContext, stringCtor);
numberPrototype->init(rootContext, numberCtor);
booleanPrototype->init(rootContext, booleanCtor);
arrayPrototype->init(rootContext, arrayCtor);
datePrototype->init(rootContext, dateCtor);
functionPrototype->init(rootContext, functionCtor);
regExpPrototype->init(rootContext, regExpCtor);
errorPrototype->init(rootContext, errorCtor);
evalErrorPrototype->init(rootContext, evalErrorCtor);
rangeErrorPrototype->init(rootContext, rangeErrorCtor);
referenceErrorPrototype->init(rootContext, referenceErrorCtor);
syntaxErrorPrototype->init(rootContext, syntaxErrorCtor);
typeErrorPrototype->init(rootContext, typeErrorCtor);
uRIErrorPrototype->init(rootContext, uRIErrorCtor);
//
// set up the global object
//
VM::Object *glo = newObject(/*rootContext*/);
globalObject = Value::fromObject(glo);
rootContext->activation = glo;
glo->__put__(rootContext, identifier(QStringLiteral("Object")), objectCtor);
glo->__put__(rootContext, identifier(QStringLiteral("String")), stringCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Number")), numberCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Boolean")), booleanCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Array")), arrayCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Function")), functionCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Date")), dateCtor);
glo->__put__(rootContext, identifier(QStringLiteral("RegExp")), regExpCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Error")), errorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("EvalError")), evalErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("RangeError")), rangeErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("ReferenceError")), referenceErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("SyntaxError")), syntaxErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("TypeError")), typeErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("URIError")), uRIErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Math")), Value::fromObject(newMathObject(rootContext)));
glo->__put__(rootContext, identifier(QStringLiteral("undefined")), Value::undefinedValue());
glo->__put__(rootContext, identifier(QStringLiteral("NaN")), Value::fromDouble(nan("")));
glo->__put__(rootContext, identifier(QStringLiteral("Infinity")), Value::fromDouble(INFINITY));
glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext)));
}
ExecutionContext *ExecutionEngine::newContext()
{
return new ExecutionContext();
}
String *ExecutionEngine::identifier(const QString &s)
{
String *&id = identifiers[s];
if (! id)
id = newString(s);
return id;
}
FunctionObject *ExecutionEngine::newNativeFunction(ExecutionContext *scope, void (*code)(ExecutionContext *))
{
NativeFunction *f = new NativeFunction(scope, code);
f->prototype = scope->engine->functionPrototype;
return f;
}
FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, IR::Function *function)
{
ScriptFunction *f = new ScriptFunction(scope, function);
Object *proto = scope->engine->newObject();
proto->__put__(scope, scope->engine->id_constructor, Value::fromObject(f));
f->__put__(scope, scope->engine->id_prototype, Value::fromObject(proto));
f->prototype = scope->engine->functionPrototype;
return f;
}
Object *ExecutionEngine::newObject()
{
Object *object = new Object();
object->prototype = objectPrototype;
return object;
}
FunctionObject *ExecutionEngine::newObjectCtor(ExecutionContext *ctx)
{
return new ObjectCtor(ctx);
}
String *ExecutionEngine::newString(const QString &s)
{
return new String(s);
}
Object *ExecutionEngine::newStringObject(const Value &value)
{
StringObject *object = new StringObject(value);
object->prototype = stringPrototype;
return object;
}
FunctionObject *ExecutionEngine::newStringCtor(ExecutionContext *ctx)
{
return new StringCtor(ctx);
}
Object *ExecutionEngine::newNumberObject(const Value &value)
{
NumberObject *object = new NumberObject(value);
object->prototype = numberPrototype;
return object;
}
FunctionObject *ExecutionEngine::newNumberCtor(ExecutionContext *ctx)
{
return new NumberCtor(ctx);
}
Object *ExecutionEngine::newBooleanObject(const Value &value)
{
Object *object = new BooleanObject(value);
object->prototype = booleanPrototype;
return object;
}
FunctionObject *ExecutionEngine::newBooleanCtor(ExecutionContext *ctx)
{
return new BooleanCtor(ctx);
}
Object *ExecutionEngine::newFunctionObject(ExecutionContext *ctx)
{
Object *object = new FunctionObject(ctx);
object->prototype = functionPrototype;
return object;
}
FunctionObject *ExecutionEngine::newFunctionCtor(ExecutionContext *ctx)
{
return new FunctionCtor(ctx);
}
Object *ExecutionEngine::newArrayObject()
{
ArrayObject *object = new ArrayObject();
object->prototype = arrayPrototype;
return object;
}
Object *ExecutionEngine::newArrayObject(const Array &value)
{
ArrayObject *object = new ArrayObject(value);
object->prototype = arrayPrototype;
return object;
}
FunctionObject *ExecutionEngine::newArrayCtor(ExecutionContext *ctx)
{
return new ArrayCtor(ctx);
}
Object *ExecutionEngine::newDateObject(const Value &value)
{
Object *object = new DateObject(value);
object->prototype = datePrototype;
return object;
}
FunctionObject *ExecutionEngine::newDateCtor(ExecutionContext *ctx)
{
return new DateCtor(ctx);
}
Object *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
bool global = (flags & IR::RegExp::RegExp_Global);
QRegularExpression::PatternOptions options = 0;
if (flags & IR::RegExp::RegExp_IgnoreCase)
options |= QRegularExpression::CaseInsensitiveOption;
if (flags & IR::RegExp::RegExp_Multiline)
options |= QRegularExpression::MultilineOption;
Object *object = new RegExpObject(QRegularExpression(pattern, options), global);
object->prototype = regExpPrototype;
return object;
}
FunctionObject *ExecutionEngine::newRegExpCtor(ExecutionContext *ctx)
{
return new RegExpCtor(ctx);
}
Object *ExecutionEngine::newErrorObject(const Value &value)
{
ErrorObject *object = new ErrorObject(value);
object->prototype = errorPrototype;
return object;
}
Object *ExecutionEngine::newMathObject(ExecutionContext *ctx)
{
MathObject *object = new MathObject(ctx);
object->prototype = objectPrototype;
return object;
}
Object *ExecutionEngine::newActivationObject(ExecutionContext *ctx)
{
return new ActivationObject(ctx);
}
Object *ExecutionEngine::newForEachIteratorObject(Object *o)
{
return new ForEachIteratorObject(o);
}
} // namespace VM
} // namespace QQmlJS

182
qmljs_engine.h Normal file
View File

@ -0,0 +1,182 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#ifndef QMLJS_ENGINE_H
#define QMLJS_ENGINE_H
#include <qmljs_objects.h>
#include <setjmp.h>
namespace QQmlJS {
namespace VM {
struct Value;
struct Array;
struct Object;
struct BooleanObject;
struct NumberObject;
struct StringObject;
struct ArrayObject;
struct DateObject;
struct FunctionObject;
struct RegExpObject;
struct ErrorObject;
struct ActivationObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
struct ObjectPrototype;
struct StringPrototype;
struct NumberPrototype;
struct BooleanPrototype;
struct ArrayPrototype;
struct FunctionPrototype;
struct DatePrototype;
struct RegExpPrototype;
struct ErrorPrototype;
struct EvalErrorPrototype;
struct RangeErrorPrototype;
struct ReferenceErrorPrototype;
struct SyntaxErrorPrototype;
struct TypeErrorPrototype;
struct URIErrorPrototype;
struct ExecutionEngine
{
ExecutionContext *rootContext;
Value globalObject;
Value objectCtor;
Value stringCtor;
Value numberCtor;
Value booleanCtor;
Value arrayCtor;
Value functionCtor;
Value dateCtor;
Value regExpCtor;
Value errorCtor;
Value evalErrorCtor;
Value rangeErrorCtor;
Value referenceErrorCtor;
Value syntaxErrorCtor;
Value typeErrorCtor;
Value uRIErrorCtor;
ObjectPrototype *objectPrototype;
StringPrototype *stringPrototype;
NumberPrototype *numberPrototype;
BooleanPrototype *booleanPrototype;
ArrayPrototype *arrayPrototype;
FunctionPrototype *functionPrototype;
DatePrototype *datePrototype;
RegExpPrototype *regExpPrototype;
ErrorPrototype *errorPrototype;
EvalErrorPrototype *evalErrorPrototype;
RangeErrorPrototype *rangeErrorPrototype;
ReferenceErrorPrototype *referenceErrorPrototype;
SyntaxErrorPrototype *syntaxErrorPrototype;
TypeErrorPrototype *typeErrorPrototype;
URIErrorPrototype *uRIErrorPrototype;
QHash<QString, String *> identifiers;
String *id_length;
String *id_prototype;
String *id_constructor;
String *id_arguments;
String *id___proto__;
struct ExceptionHandler {
ExecutionContext *context;
const uchar *code; // Interpreter state
int targetTempIndex; // Interpreter state
jmp_buf stackFrame;
};
QVector<ExceptionHandler> unwindStack;
ExecutionEngine();
ExecutionContext *newContext();
String *identifier(const QString &s);
FunctionObject *newNativeFunction(ExecutionContext *scope, void (*code)(ExecutionContext *));
FunctionObject *newScriptFunction(ExecutionContext *scope, IR::Function *function);
Object *newObject();
FunctionObject *newObjectCtor(ExecutionContext *ctx);
String *newString(const QString &s);
Object *newStringObject(const Value &value);
FunctionObject *newStringCtor(ExecutionContext *ctx);
Object *newNumberObject(const Value &value);
FunctionObject *newNumberCtor(ExecutionContext *ctx);
Object *newBooleanObject(const Value &value);
FunctionObject *newBooleanCtor(ExecutionContext *ctx);
Object *newFunctionObject(ExecutionContext *ctx);
FunctionObject *newFunctionCtor(ExecutionContext *ctx);
Object *newArrayObject();
Object *newArrayObject(const Array &value);
FunctionObject *newArrayCtor(ExecutionContext *ctx);
Object *newDateObject(const Value &value);
FunctionObject *newDateCtor(ExecutionContext *ctx);
Object *newRegExpObject(const QString &pattern, int flags);
FunctionObject *newRegExpCtor(ExecutionContext *ctx);
Object *newErrorObject(const Value &value);
Object *newMathObject(ExecutionContext *ctx);
Object *newActivationObject(ExecutionContext *ctx);
Object *newForEachIteratorObject(Object *o);
};
} // namespace VM
} // namespace QQmlJS
#endif

181
qmljs_environment.cpp Normal file
View File

@ -0,0 +1,181 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include <qmljs_environment.h>
#include <qmljs_objects.h>
#include <qv4ecmaobjects_p.h>
namespace QQmlJS {
namespace VM {
void ExecutionContext::init(ExecutionEngine *eng)
{
engine = eng;
parent = 0;
arguments = 0;
argumentCount = 0;
locals = 0;
activation = 0;
thisObject = Value::nullValue();
result = Value::undefinedValue();
formals = 0;
formalCount = 0;
vars = 0;
varCount = 0;
}
PropertyDescriptor *ExecutionContext::lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp)
{
for (ExecutionContext *ctx = this; ctx; ctx = ctx->parent) {
if (ctx->activation) {
if (PropertyDescriptor *pd = ctx->activation->__getPropertyDescriptor__(this, name, tmp))
return pd;
}
}
return 0;
}
void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op)
{
for (ExecutionContext *ctx = this; ctx; ctx = ctx->parent) {
if (ctx->activation) {
if (ctx->activation->inplaceBinOp(value, name, op, this))
return;
}
}
throwReferenceError(Value::fromString(name));
}
void ExecutionContext::throwError(Value value)
{
result = value;
__qmljs_builtin_throw(value, this);
}
void ExecutionContext::throwError(const QString &message)
{
Value v = Value::fromString(this, message);
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwTypeError()
{
Value v = Value::fromString(this, QStringLiteral("Type error"));
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwUnimplemented(const QString &message)
{
Value v = Value::fromString(this, QStringLiteral("Unimplemented ") + message);
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwReferenceError(Value value)
{
String *s = value.toString(this);
QString msg = s->toQString() + QStringLiteral(" is not defined");
throwError(Value::fromObject(engine->newErrorObject(Value::fromString(this, msg))));
}
void ExecutionContext::initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc)
{
engine = parent->engine;
this->parent = f->scope;
assert(this->parent == f->scope);
result = Value::undefinedValue();
if (f->needsActivation)
activation = engine->newActivationObject(this);
else
activation = 0;
thisObject = that;
formals = f->formalParameterList;
formalCount = f->formalParameterCount;
arguments = args;
argumentCount = argc;
if (f->needsActivation || argc < formalCount){
arguments = new Value[qMax(argc, formalCount)];
if (argc)
std::copy(args, args + argc, arguments);
if (argc < formalCount)
std::fill(arguments + argc, arguments + formalCount, Value::undefinedValue());
}
vars = f->varList;
varCount = f->varCount;
locals = varCount ? new Value[varCount] : 0;
if (varCount)
std::fill(locals, locals + varCount, Value::undefinedValue());
}
void ExecutionContext::leaveCallContext()
{
if (activation) {
delete[] locals;
locals = 0;
}
}
void ExecutionContext::initConstructorContext(ExecutionContext *parent, Value that, FunctionObject *f, Value *args, unsigned argc)
{
initCallContext(parent, that, f, args, argc);
}
void ExecutionContext::leaveConstructorContext(FunctionObject *f)
{
wireUpPrototype(f);
leaveCallContext();
}
void ExecutionContext::wireUpPrototype(FunctionObject *f)
{
assert(thisObject.isObject());
result = thisObject;
Value proto = f->__get__(this, engine->id_prototype);
thisObject.objectValue()->prototype = proto.objectValue();
if (! thisObject.isObject())
thisObject.objectValue()->prototype = engine->objectPrototype;
}
} // namespace VM
} // namespace QQmlJS

98
qmljs_environment.h Normal file
View File

@ -0,0 +1,98 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#ifndef QMLJS_ENVIRONMENT_H
#define QMLJS_ENVIRONMENT_H
#include <qmljs_runtime.h>
namespace QQmlJS {
namespace VM {
struct Value;
struct Object;
struct ExecutionEngine;
struct ExecutionContext;
struct ExecutionContext {
ExecutionEngine *engine;
ExecutionContext *parent;
Object *activation;
Value thisObject;
Value *arguments;
unsigned int argumentCount;
Value *locals;
Value result;
String **formals;
unsigned int formalCount;
String **vars;
unsigned int varCount;
PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp);
void inplaceBitOp(Value value, String *name, BinOp op);
inline Value argument(unsigned int index = 0)
{
if (index < argumentCount)
return arguments[index];
return Value::undefinedValue();
}
void init(ExecutionEngine *eng);
void initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc);
void leaveCallContext();
void initConstructorContext(ExecutionContext *parent, Value that, FunctionObject *f, Value *args, unsigned argc);
void leaveConstructorContext(FunctionObject *f);
void wireUpPrototype(FunctionObject *f);
void throwError(Value value);
void throwError(const QString &message);
void throwTypeError();
void throwReferenceError(Value value);
void throwUnimplemented(const QString &message);
};
} // namespace VM
} // namespace QQmlJS
#endif

View File

@ -686,292 +686,3 @@ PropertyDescriptor *ArgumentsObject::__getPropertyDescriptor__(ExecutionContext
return Object::__getPropertyDescriptor__(ctx, name, to_fill);
}
ExecutionEngine::ExecutionEngine()
{
rootContext = newContext();
rootContext->init(this);
id_length = identifier(QStringLiteral("length"));
id_prototype = identifier(QStringLiteral("prototype"));
id_constructor = identifier(QStringLiteral("constructor"));
id_arguments = identifier(QStringLiteral("arguments"));
id___proto__ = identifier(QStringLiteral("__proto__"));
objectPrototype = new ObjectPrototype();
stringPrototype = new StringPrototype(rootContext);
numberPrototype = new NumberPrototype();
booleanPrototype = new BooleanPrototype();
arrayPrototype = new ArrayPrototype();
datePrototype = new DatePrototype();
functionPrototype = new FunctionPrototype(rootContext);
regExpPrototype = new RegExpPrototype();
errorPrototype = new ErrorPrototype();
evalErrorPrototype = new EvalErrorPrototype(rootContext);
rangeErrorPrototype = new RangeErrorPrototype(rootContext);
referenceErrorPrototype = new ReferenceErrorPrototype(rootContext);
syntaxErrorPrototype = new SyntaxErrorPrototype(rootContext);
typeErrorPrototype = new TypeErrorPrototype(rootContext);
uRIErrorPrototype = new URIErrorPrototype(rootContext);
stringPrototype->prototype = objectPrototype;
numberPrototype->prototype = objectPrototype;
booleanPrototype->prototype = objectPrototype;
arrayPrototype->prototype = objectPrototype;
datePrototype->prototype = objectPrototype;
functionPrototype->prototype = objectPrototype;
regExpPrototype->prototype = objectPrototype;
errorPrototype->prototype = objectPrototype;
evalErrorPrototype->prototype = errorPrototype;
rangeErrorPrototype->prototype = errorPrototype;
referenceErrorPrototype->prototype = errorPrototype;
syntaxErrorPrototype->prototype = errorPrototype;
typeErrorPrototype->prototype = errorPrototype;
uRIErrorPrototype->prototype = errorPrototype;
objectCtor = Value::fromObject(new ObjectCtor(rootContext));
stringCtor = Value::fromObject(new StringCtor(rootContext));
numberCtor = Value::fromObject(new NumberCtor(rootContext));
booleanCtor = Value::fromObject(new BooleanCtor(rootContext));
arrayCtor = Value::fromObject(new ArrayCtor(rootContext));
functionCtor = Value::fromObject(new FunctionCtor(rootContext));
dateCtor = Value::fromObject(new DateCtor(rootContext));
regExpCtor = Value::fromObject(new RegExpCtor(rootContext));
errorCtor = Value::fromObject(new ErrorCtor(rootContext));
evalErrorCtor = Value::fromObject(new EvalErrorCtor(rootContext));
rangeErrorCtor = Value::fromObject(new RangeErrorCtor(rootContext));
referenceErrorCtor = Value::fromObject(new ReferenceErrorCtor(rootContext));
syntaxErrorCtor = Value::fromObject(new SyntaxErrorCtor(rootContext));
typeErrorCtor = Value::fromObject(new TypeErrorCtor(rootContext));
uRIErrorCtor = Value::fromObject(new URIErrorCtor(rootContext));
stringCtor.objectValue()->prototype = functionPrototype;
numberCtor.objectValue()->prototype = functionPrototype;
booleanCtor.objectValue()->prototype = functionPrototype;
arrayCtor.objectValue()->prototype = functionPrototype;
functionCtor.objectValue()->prototype = functionPrototype;
dateCtor.objectValue()->prototype = functionPrototype;
regExpCtor.objectValue()->prototype = functionPrototype;
errorCtor.objectValue()->prototype = functionPrototype;
evalErrorCtor.objectValue()->prototype = errorPrototype;
rangeErrorCtor.objectValue()->prototype = errorPrototype;
referenceErrorCtor.objectValue()->prototype = errorPrototype;
syntaxErrorCtor.objectValue()->prototype = errorPrototype;
typeErrorCtor.objectValue()->prototype = errorPrototype;
uRIErrorCtor.objectValue()->prototype = errorPrototype;
objectPrototype->init(rootContext, objectCtor);
stringPrototype->init(rootContext, stringCtor);
numberPrototype->init(rootContext, numberCtor);
booleanPrototype->init(rootContext, booleanCtor);
arrayPrototype->init(rootContext, arrayCtor);
datePrototype->init(rootContext, dateCtor);
functionPrototype->init(rootContext, functionCtor);
regExpPrototype->init(rootContext, regExpCtor);
errorPrototype->init(rootContext, errorCtor);
evalErrorPrototype->init(rootContext, evalErrorCtor);
rangeErrorPrototype->init(rootContext, rangeErrorCtor);
referenceErrorPrototype->init(rootContext, referenceErrorCtor);
syntaxErrorPrototype->init(rootContext, syntaxErrorCtor);
typeErrorPrototype->init(rootContext, typeErrorCtor);
uRIErrorPrototype->init(rootContext, uRIErrorCtor);
//
// set up the global object
//
VM::Object *glo = newObject(/*rootContext*/);
globalObject = Value::fromObject(glo);
rootContext->activation = glo;
glo->__put__(rootContext, identifier(QStringLiteral("Object")), objectCtor);
glo->__put__(rootContext, identifier(QStringLiteral("String")), stringCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Number")), numberCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Boolean")), booleanCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Array")), arrayCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Function")), functionCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Date")), dateCtor);
glo->__put__(rootContext, identifier(QStringLiteral("RegExp")), regExpCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Error")), errorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("EvalError")), evalErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("RangeError")), rangeErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("ReferenceError")), referenceErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("SyntaxError")), syntaxErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("TypeError")), typeErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("URIError")), uRIErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Math")), Value::fromObject(newMathObject(rootContext)));
glo->__put__(rootContext, identifier(QStringLiteral("undefined")), Value::undefinedValue());
glo->__put__(rootContext, identifier(QStringLiteral("NaN")), Value::fromDouble(nan("")));
glo->__put__(rootContext, identifier(QStringLiteral("Infinity")), Value::fromDouble(INFINITY));
glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext)));
}
ExecutionContext *ExecutionEngine::newContext()
{
return new ExecutionContext();
}
String *ExecutionEngine::identifier(const QString &s)
{
String *&id = identifiers[s];
if (! id)
id = newString(s);
return id;
}
FunctionObject *ExecutionEngine::newNativeFunction(ExecutionContext *scope, void (*code)(ExecutionContext *))
{
NativeFunction *f = new NativeFunction(scope, code);
f->prototype = scope->engine->functionPrototype;
return f;
}
FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, IR::Function *function)
{
ScriptFunction *f = new ScriptFunction(scope, function);
Object *proto = scope->engine->newObject();
proto->__put__(scope, scope->engine->id_constructor, Value::fromObject(f));
f->__put__(scope, scope->engine->id_prototype, Value::fromObject(proto));
f->prototype = scope->engine->functionPrototype;
return f;
}
Object *ExecutionEngine::newObject()
{
Object *object = new Object();
object->prototype = objectPrototype;
return object;
}
FunctionObject *ExecutionEngine::newObjectCtor(ExecutionContext *ctx)
{
return new ObjectCtor(ctx);
}
String *ExecutionEngine::newString(const QString &s)
{
return new String(s);
}
Object *ExecutionEngine::newStringObject(const Value &value)
{
StringObject *object = new StringObject(value);
object->prototype = stringPrototype;
return object;
}
FunctionObject *ExecutionEngine::newStringCtor(ExecutionContext *ctx)
{
return new StringCtor(ctx);
}
Object *ExecutionEngine::newNumberObject(const Value &value)
{
NumberObject *object = new NumberObject(value);
object->prototype = numberPrototype;
return object;
}
FunctionObject *ExecutionEngine::newNumberCtor(ExecutionContext *ctx)
{
return new NumberCtor(ctx);
}
Object *ExecutionEngine::newBooleanObject(const Value &value)
{
Object *object = new BooleanObject(value);
object->prototype = booleanPrototype;
return object;
}
FunctionObject *ExecutionEngine::newBooleanCtor(ExecutionContext *ctx)
{
return new BooleanCtor(ctx);
}
Object *ExecutionEngine::newFunctionObject(ExecutionContext *ctx)
{
Object *object = new FunctionObject(ctx);
object->prototype = functionPrototype;
return object;
}
FunctionObject *ExecutionEngine::newFunctionCtor(ExecutionContext *ctx)
{
return new FunctionCtor(ctx);
}
Object *ExecutionEngine::newArrayObject()
{
ArrayObject *object = new ArrayObject();
object->prototype = arrayPrototype;
return object;
}
Object *ExecutionEngine::newArrayObject(const Array &value)
{
ArrayObject *object = new ArrayObject(value);
object->prototype = arrayPrototype;
return object;
}
FunctionObject *ExecutionEngine::newArrayCtor(ExecutionContext *ctx)
{
return new ArrayCtor(ctx);
}
Object *ExecutionEngine::newDateObject(const Value &value)
{
Object *object = new DateObject(value);
object->prototype = datePrototype;
return object;
}
FunctionObject *ExecutionEngine::newDateCtor(ExecutionContext *ctx)
{
return new DateCtor(ctx);
}
Object *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
bool global = (flags & IR::RegExp::RegExp_Global);
QRegularExpression::PatternOptions options = 0;
if (flags & IR::RegExp::RegExp_IgnoreCase)
options |= QRegularExpression::CaseInsensitiveOption;
if (flags & IR::RegExp::RegExp_Multiline)
options |= QRegularExpression::MultilineOption;
Object *object = new RegExpObject(QRegularExpression(pattern, options), global);
object->prototype = regExpPrototype;
return object;
}
FunctionObject *ExecutionEngine::newRegExpCtor(ExecutionContext *ctx)
{
return new RegExpCtor(ctx);
}
Object *ExecutionEngine::newErrorObject(const Value &value)
{
ErrorObject *object = new ErrorObject(value);
object->prototype = errorPrototype;
return object;
}
Object *ExecutionEngine::newMathObject(ExecutionContext *ctx)
{
MathObject *object = new MathObject(ctx);
object->prototype = objectPrototype;
return object;
}
Object *ExecutionEngine::newActivationObject(ExecutionContext *ctx)
{
return new ActivationObject(ctx);
}
Object *ExecutionEngine::newForEachIteratorObject(Object *o)
{
return new ForEachIteratorObject(o);
}

View File

@ -42,6 +42,8 @@
#define QMLJS_OBJECTS_H
#include "qmljs_runtime.h"
#include "qmljs_engine.h"
#include "qmljs_environment.h"
#include "qv4array_p.h"
#include "qv4codegen_p.h"
@ -50,7 +52,6 @@
#include <QtCore/QRegularExpression>
#include <cstdio>
#include <cassert>
#include <setjmp.h>
namespace QQmlJS {
@ -600,102 +601,6 @@ struct ArgumentsObject: Object {
virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
};
struct ExecutionEngine
{
ExecutionContext *rootContext;
Value globalObject;
Value objectCtor;
Value stringCtor;
Value numberCtor;
Value booleanCtor;
Value arrayCtor;
Value functionCtor;
Value dateCtor;
Value regExpCtor;
Value errorCtor;
Value evalErrorCtor;
Value rangeErrorCtor;
Value referenceErrorCtor;
Value syntaxErrorCtor;
Value typeErrorCtor;
Value uRIErrorCtor;
ObjectPrototype *objectPrototype;
StringPrototype *stringPrototype;
NumberPrototype *numberPrototype;
BooleanPrototype *booleanPrototype;
ArrayPrototype *arrayPrototype;
FunctionPrototype *functionPrototype;
DatePrototype *datePrototype;
RegExpPrototype *regExpPrototype;
ErrorPrototype *errorPrototype;
EvalErrorPrototype *evalErrorPrototype;
RangeErrorPrototype *rangeErrorPrototype;
ReferenceErrorPrototype *referenceErrorPrototype;
SyntaxErrorPrototype *syntaxErrorPrototype;
TypeErrorPrototype *typeErrorPrototype;
URIErrorPrototype *uRIErrorPrototype;
QHash<QString, String *> identifiers;
String *id_length;
String *id_prototype;
String *id_constructor;
String *id_arguments;
String *id___proto__;
struct ExceptionHandler {
ExecutionContext *context;
const uchar *code; // Interpreter state
int targetTempIndex; // Interpreter state
jmp_buf stackFrame;
};
QVector<ExceptionHandler> unwindStack;
ExecutionEngine();
ExecutionContext *newContext();
String *identifier(const QString &s);
FunctionObject *newNativeFunction(ExecutionContext *scope, void (*code)(ExecutionContext *));
FunctionObject *newScriptFunction(ExecutionContext *scope, IR::Function *function);
Object *newObject();
FunctionObject *newObjectCtor(ExecutionContext *ctx);
String *newString(const QString &s);
Object *newStringObject(const Value &value);
FunctionObject *newStringCtor(ExecutionContext *ctx);
Object *newNumberObject(const Value &value);
FunctionObject *newNumberCtor(ExecutionContext *ctx);
Object *newBooleanObject(const Value &value);
FunctionObject *newBooleanCtor(ExecutionContext *ctx);
Object *newFunctionObject(ExecutionContext *ctx);
FunctionObject *newFunctionCtor(ExecutionContext *ctx);
Object *newArrayObject();
Object *newArrayObject(const Array &value);
FunctionObject *newArrayCtor(ExecutionContext *ctx);
Object *newDateObject(const Value &value);
FunctionObject *newDateCtor(ExecutionContext *ctx);
Object *newRegExpObject(const QString &pattern, int flags);
FunctionObject *newRegExpCtor(ExecutionContext *ctx);
Object *newErrorObject(const Value &value);
Object *newMathObject(ExecutionContext *ctx);
Object *newActivationObject(ExecutionContext *ctx);
Object *newForEachIteratorObject(Object *o);
};
} // namespace VM
} // namespace QQmlJS

View File

@ -230,138 +230,6 @@ Value Value::property(ExecutionContext *ctx, String *name) const
return isObject() ? objectValue()->__get__(ctx, name) : undefinedValue();
}
void ExecutionContext::init(ExecutionEngine *eng)
{
engine = eng;
parent = 0;
arguments = 0;
argumentCount = 0;
locals = 0;
activation = 0;
thisObject = Value::nullValue();
result = Value::undefinedValue();
formals = 0;
formalCount = 0;
vars = 0;
varCount = 0;
}
PropertyDescriptor *ExecutionContext::lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp)
{
for (ExecutionContext *ctx = this; ctx; ctx = ctx->parent) {
if (ctx->activation) {
if (PropertyDescriptor *pd = ctx->activation->__getPropertyDescriptor__(this, name, tmp))
return pd;
}
}
return 0;
}
void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op)
{
for (ExecutionContext *ctx = this; ctx; ctx = ctx->parent) {
if (ctx->activation) {
if (ctx->activation->inplaceBinOp(value, name, op, this))
return;
}
}
throwReferenceError(Value::fromString(name));
}
void ExecutionContext::throwError(Value value)
{
result = value;
__qmljs_builtin_throw(value, this);
}
void ExecutionContext::throwError(const QString &message)
{
Value v = Value::fromString(this, message);
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwTypeError()
{
Value v = Value::fromString(this, QStringLiteral("Type error"));
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwUnimplemented(const QString &message)
{
Value v = Value::fromString(this, QStringLiteral("Unimplemented ") + message);
throwError(Value::fromObject(engine->newErrorObject(v)));
}
void ExecutionContext::throwReferenceError(Value value)
{
String *s = value.toString(this);
QString msg = s->toQString() + QStringLiteral(" is not defined");
throwError(Value::fromObject(engine->newErrorObject(Value::fromString(this, msg))));
}
void ExecutionContext::initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc)
{
engine = parent->engine;
this->parent = f->scope;
assert(this->parent == f->scope);
result = Value::undefinedValue();
if (f->needsActivation)
activation = engine->newActivationObject(this);
else
activation = 0;
thisObject = that;
formals = f->formalParameterList;
formalCount = f->formalParameterCount;
arguments = args;
argumentCount = argc;
if (f->needsActivation || argc < formalCount){
arguments = new Value[qMax(argc, formalCount)];
if (argc)
std::copy(args, args + argc, arguments);
if (argc < formalCount)
std::fill(arguments + argc, arguments + formalCount, Value::undefinedValue());
}
vars = f->varList;
varCount = f->varCount;
locals = varCount ? new Value[varCount] : 0;
if (varCount)
std::fill(locals, locals + varCount, Value::undefinedValue());
}
void ExecutionContext::leaveCallContext()
{
if (activation) {
delete[] locals;
locals = 0;
}
}
void ExecutionContext::initConstructorContext(ExecutionContext *parent, Value that, FunctionObject *f, Value *args, unsigned argc)
{
initCallContext(parent, that, f, args, argc);
}
void ExecutionContext::leaveConstructorContext(FunctionObject *f)
{
wireUpPrototype(f);
leaveCallContext();
}
void ExecutionContext::wireUpPrototype(FunctionObject *f)
{
assert(thisObject.isObject());
result = thisObject;
Value proto = f->__get__(this, engine->id_prototype);
thisObject.objectValue()->prototype = proto.objectValue();
if (! thisObject.isObject())
thisObject.objectValue()->prototype = engine->objectPrototype;
}
extern "C" {
Value __qmljs_init_closure(IR::Function *clos, ExecutionContext *ctx)

View File

@ -570,47 +570,6 @@ inline bool Value::sameValue(Value other) {
#include <qmljs_math.h>
struct ExecutionContext {
ExecutionEngine *engine;
ExecutionContext *parent;
Object *activation;
Value thisObject;
Value *arguments;
unsigned int argumentCount;
Value *locals;
Value result;
String **formals;
unsigned int formalCount;
String **vars;
unsigned int varCount;
PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp);
void inplaceBitOp(Value value, String *name, BinOp op);
inline Value argument(unsigned int index = 0)
{
if (index < argumentCount)
return arguments[index];
return Value::undefinedValue();
}
void init(ExecutionEngine *eng);
void initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc);
void leaveCallContext();
void initConstructorContext(ExecutionContext *parent, Value that, FunctionObject *f, Value *args, unsigned argc);
void leaveConstructorContext(FunctionObject *f);
void wireUpPrototype(FunctionObject *f);
void throwError(Value value);
void throwError(const QString &message);
void throwTypeError();
void throwReferenceError(Value value);
void throwUnimplemented(const QString &message);
};
extern "C" {

4
v4.pro
View File

@ -13,6 +13,8 @@ LIBS += -rdynamic
SOURCES += main.cpp \
qv4codegen.cpp \
qv4ir.cpp \
qmljs_engine.cpp \
qmljs_environment.cpp \
qmljs_runtime.cpp \
qmljs_objects.cpp \
qv4syntaxchecker.cpp \
@ -24,6 +26,8 @@ SOURCES += main.cpp \
HEADERS += \
qv4codegen_p.h \
qv4ir_p.h \
qmljs_engine.h \
qmljs_environment.h \
qmljs_runtime.h \
qmljs_objects.h \
qmljs_math.h \