} // builtins
-void evaluate(QQmlJS::Engine *engine, const QString &fileName, const QString &code)
+void evaluate(QQmlJS::VM::ExecutionEngine *vm, QQmlJS::Engine *engine, const QString &fileName, const QString &code)
{
using namespace QQmlJS;
const size_t codeSize = 10 * getpagesize();
uchar *code = (uchar *) malloc(codeSize);
- x86_64::InstructionSelection isel(&module, code);
+ x86_64::InstructionSelection isel(vm, &module, code);
QHash<QString, IR::Function *> codeByName;
foreach (IR::Function *function, module.functions) {
isel(function);
if (! protect(code, codeSize))
Q_UNREACHABLE();
- VM::Context *ctx = new VM::Context;
- ctx->init();
+ VM::Object *globalObject = vm->globalObject.objectValue;
+ VM::Context *ctx = vm->rootContext;
- VM::String *prototype = VM::String::get(ctx, QLatin1String("prototype"));
-
- VM::Object *globalObject = new VM::ArgumentsObject(ctx);
- __qmljs_init_object(ctx, &ctx->activation, globalObject);
-
- globalObject->put(VM::String::get(ctx, QLatin1String("print")),
+ globalObject->put(vm->identifier(QLatin1String("print")),
VM::Value::object(ctx, new builtins::Print(ctx)));
- globalObject->put(VM::String::get(ctx, QLatin1String("Object")),
- VM::Value::object(ctx, new builtins::ObjectCtor(ctx)));
-
- VM::FunctionObject *stringCtor = new VM::StringCtor(ctx);
- stringCtor->put(prototype, VM::Value::object(ctx, new VM::StringPrototype(ctx, stringCtor)));
- globalObject->put(VM::String::get(ctx, QLatin1String("String")), VM::Value::object(ctx, stringCtor));
-
- VM::FunctionObject *numberCtor = new VM::NumberCtor(ctx);
- numberCtor->put(prototype, VM::Value::object(ctx, new VM::NumberPrototype(ctx, numberCtor)));
- globalObject->put(VM::String::get(ctx, QLatin1String("Number")), VM::Value::object(ctx, numberCtor));
-
foreach (IR::Function *function, module.functions) {
if (function->name && ! function->name->isEmpty()) {
- globalObject->put(VM::String::get(ctx, *function->name),
+ globalObject->put(vm->identifier(*function->name),
VM::Value::object(ctx, new VM::ScriptFunction(ctx, function)));
}
}
QStringList args = app.arguments();
args.removeFirst();
+ VM::ExecutionEngine vm;
Engine engine;
foreach (const QString &fn, args) {
QFile file(fn);
if (file.open(QFile::ReadOnly)) {
const QString code = QString::fromUtf8(file.readAll());
file.close();
- evaluate(&engine, fn, code);
+ evaluate(&vm, &engine, fn, code);
}
}
}
#include "qmljs_objects.h"
#include "qv4ir_p.h"
+#include "qv4ecmaobjects_p.h"
#include <QtCore/QDebug>
#include <cassert>
void Object::setProperty(Context *ctx, const QString &name, const Value &value)
{
- put(String::get(ctx, name), value);
+ put(ctx->engine->identifier(name), value);
}
void Object::setProperty(Context *ctx, const QString &name, void (*code)(Context *))
return false;
}
-void Object::defaultValue(Value *result, int typeHint)
+void Object::defaultValue(Context *ctx, Value *result, int typeHint)
{
- Context *ctx = 0; // ###
-
if (typeHint == STRING_HINT) {
if (asFunctionObject() != 0)
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("function")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("function")));
else
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("object")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("object")));
} else {
__qmljs_init_undefined(ctx, result);
}
if (formalParameterCount) {
formalParameterList = new String*[formalParameterCount];
for (size_t i = 0; i < formalParameterCount; ++i) {
- formalParameterList[i] = String::get(0, *function->formals.at(i)); // ### unique
+ formalParameterList[i] = scope->engine->identifier(*function->formals.at(i));
}
}
}
return prop;
return 0;
}
+
+ExecutionEngine::ExecutionEngine()
+{
+ rootContext = new VM::Context;
+ rootContext->init(this);
+
+ //
+ // set up the global object
+ //
+ VM::Object *glo = new VM::ArgumentsObject(rootContext);
+ __qmljs_init_object(rootContext, &globalObject, glo);
+ __qmljs_init_object(rootContext, &rootContext->activation, glo);
+
+ objectCtor = ObjectCtor::create(this);
+ stringCtor = StringCtor::create(this);
+ numberCtor = NumberCtor::create(this);
+
+ String *prototype = String::get(rootContext, QLatin1String("prototype"));
+
+ objectCtor.objectValue->get(prototype, &objectPrototype);
+ stringCtor.objectValue->get(prototype, &stringPrototype);
+ numberCtor.objectValue->get(prototype, &numberPrototype);
+
+ glo->put(VM::String::get(rootContext, QLatin1String("Object")), objectCtor);
+ glo->put(VM::String::get(rootContext, QLatin1String("String")), stringCtor);
+ glo->put(VM::String::get(rootContext, QLatin1String("Number")), numberCtor);
+}
+
+String *ExecutionEngine::identifier(const QString &s)
+{
+ String *&id = identifiers[s];
+ if (! id)
+ id = new String(s);
+ return id;
+}
struct ArrayObject;
struct FunctionObject;
struct ErrorObject;
+struct Context;
+struct ExecutionEngine;
struct String {
String(const QString &text)
virtual bool canPut(String *name);
virtual bool hasProperty(String *name) const;
virtual bool deleteProperty(String *name, bool flag);
- virtual void defaultValue(Value *result, int typeHint);
+ virtual void defaultValue(Context *ctx, Value *result, int typeHint);
// ### TODO: defineOwnProperty(name, descriptor, boolean) -> boolean
//
struct BooleanObject: Object {
Value value;
BooleanObject(const Value &value): value(value) {}
- virtual void defaultValue(Value *result, int /*typehint*/) { *result = value; }
+ virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
};
struct NumberObject: Object {
Value value;
NumberObject(const Value &value): value(value) {}
- virtual void defaultValue(Value *result, int /*typehint*/) { *result = value; }
+ virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
};
struct StringObject: Object {
Value value;
StringObject(const Value &value): value(value) {}
- virtual void defaultValue(Value *result, int /*typehint*/) { *result = value; }
+ virtual void defaultValue(Context *, Value *result, int /*typehint*/) { *result = value; }
};
struct ArrayObject: Object {
};
struct Context {
+ ExecutionEngine *engine;
Context *parent;
Value activation;
Value thisObject;
__qmljs_init_undefined(this, result);
}
- void init()
+ void init(ExecutionEngine *eng)
{
+ engine = eng;
parent = 0;
arguments = 0;
argumentCount = 0;
}
};
+struct ExecutionEngine
+{
+ Context *rootContext;
+ Value globalObject;
+
+ Value objectCtor;
+ Value stringCtor;
+ Value numberCtor;
+
+ Value objectPrototype;
+ Value stringPrototype;
+ Value numberPrototype;
+
+ QHash<QString, String *> identifiers;
+
+ ExecutionEngine();
+
+ String *identifier(const QString &s);
+};
+
} // namespace VM
} // namespace QQmlJS
void __qmljs_string_literal_undefined(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("undefined")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("undefined")));
}
void __qmljs_string_literal_null(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("null")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("null")));
}
void __qmljs_string_literal_true(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("true")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("true")));
}
void __qmljs_string_literal_false(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("false")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("false")));
}
void __qmljs_string_literal_object(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("object")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("object")));
}
void __qmljs_string_literal_boolean(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("boolean")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("boolean")));
}
void __qmljs_string_literal_number(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("number")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("number")));
}
void __qmljs_string_literal_string(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("string")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("string")));
}
void __qmljs_string_literal_function(Context *ctx, Value *result)
{
- __qmljs_init_string(ctx, result, String::get(ctx, QLatin1String("function")));
+ __qmljs_init_string(ctx, result, ctx->engine->identifier(QLatin1String("function")));
}
void __qmljs_delete(Context *ctx, Value *result, const Value *value)
void __qmljs_object_default_value(Context *ctx, Value *result, Object *object, int typeHint)
{
Q_UNUSED(ctx);
- object->defaultValue(result, typeHint);
+ object->defaultValue(ctx, result, typeHint);
}
void __qmljs_throw_type_error(Context *ctx, Value *result)
Value value;
__qmljs_init_number(ctx, &value, number);
__qmljs_init_object(ctx, result, new NumberObject(value));
+ result->objectValue->prototype = ctx->engine->numberPrototype.objectValue;
}
void __qmljs_new_string_object(Context *ctx, Value *result, String *string)
Value value;
__qmljs_init_string(ctx, &value, string);
__qmljs_init_object(ctx, result, new StringObject(value));
+ result->objectValue->prototype = ctx->engine->stringPrototype.objectValue;
}
void __qmljs_set_property(Context *ctx, Value *object, String *name, Value *value)
if (func.type == OBJECT_TYPE) {
if (FunctionObject *f = func.objectValue->asFunctionObject()) {
Context *ctx = new Context;
- ctx->init();
+ ctx->init(context->engine);
ctx->parent = f->scope;
if (f->needsActivation)
__qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
if (func->type == OBJECT_TYPE) {
if (FunctionObject *f = func->objectValue->asFunctionObject()) {
Context *ctx = new Context;
- ctx->init();
+ ctx->init(context->engine);
ctx->parent = f->scope;
if (f->needsActivation)
__qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
if (func->type == OBJECT_TYPE) {
if (FunctionObject *f = func->objectValue->asFunctionObject()) {
Context *ctx = new Context;
- ctx->init();
+ ctx->init(context->engine);
ctx->parent = f->scope;
if (f->needsActivation)
__qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
assert(ctx->thisObject.is(OBJECT_TYPE));
ctx->result = ctx->thisObject;
Value proto;
- if (f->get(String::get(ctx, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
+ if (f->get(ctx->engine->identifier(QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
if (proto.type == OBJECT_TYPE)
ctx->thisObject.objectValue->prototype = proto.objectValue;
}
if (func.type == OBJECT_TYPE) {
if (FunctionObject *f = func.objectValue->asFunctionObject()) {
Context *ctx = new Context;
- ctx->init();
+ ctx->init(context->engine);
ctx->parent = f->scope;
if (f->needsActivation)
__qmljs_init_object(ctx, &ctx->activation, new ArgumentsObject(ctx));
assert(ctx->thisObject.is(OBJECT_TYPE));
Value proto;
- if (f->get(String::get(ctx, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
+ if (f->get(ctx->engine->identifier(QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
if (proto.type == OBJECT_TYPE)
ctx->thisObject.objectValue->prototype = proto.objectValue;
}
//
// Object
//
+Value ObjectCtor::create(ExecutionEngine *engine)
+{
+ Context *ctx = engine->rootContext;
+ ObjectCtor *ctor = new ObjectCtor(ctx);
+ ctor->setProperty(ctx, QLatin1String("prototype"), Value::object(ctx, new ObjectPrototype(ctx, ctor)));
+ return Value::object(ctx, ctor);
+}
+
ObjectCtor::ObjectCtor(Context *scope)
: FunctionObject(scope)
{
assert(!"not here");
}
-
ObjectPrototype::ObjectPrototype(Context *ctx, FunctionObject *ctor)
{
setProperty(ctx, QLatin1String("constructor"), Value::object(ctx, ctor));
//
// String
//
+Value StringCtor::create(ExecutionEngine *engine)
+{
+ Context *ctx = engine->rootContext;
+ StringCtor *ctor = new StringCtor(ctx);
+ ctor->setProperty(ctx, QLatin1String("prototype"), Value::object(ctx, new StringPrototype(ctx, ctor)));
+ return Value::object(ctx, ctor);
+}
+
StringCtor::StringCtor(Context *scope)
: FunctionObject(scope)
{
void StringPrototype::method_valueOf(Context *ctx)
{
- ctx->thisObject.objectValue->defaultValue(&ctx->result, STRING_HINT);
+ ctx->thisObject.objectValue->defaultValue(ctx, &ctx->result, STRING_HINT);
}
void StringPrototype::method_charAt(Context *ctx)
//
// Number object
//
+Value NumberCtor::create(ExecutionEngine *engine)
+{
+ Context *ctx = engine->rootContext;
+ NumberCtor *ctor = new NumberCtor(ctx);
+ ctor->setProperty(ctx, QLatin1String("prototype"), Value::object(ctx, new NumberPrototype(ctx, ctor)));
+ return Value::object(ctx, ctor);
+}
+
NumberCtor::NumberCtor(Context *scope)
: FunctionObject(scope)
{
// .arg(radix));
if (radix != 10) {
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
QString str;
double num = internalValue.toNumber(ctx);
}
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
String *str = internalValue.toString(ctx);
ctx->result = Value::string(ctx, str);
// context, QLatin1String("Number.prototype.toLocaleString"));
// }
Value internalValue;
- self.objectValue->defaultValue(&internalValue, STRING_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, STRING_HINT);
String *str = internalValue.toString(ctx);
ctx->result = Value::string(ctx, str);
}
// context, QLatin1String("Number.prototype.toLocaleString"));
// }
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
ctx->result = internalValue;
}
fdigits = 0;
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
double v = internalValue.toNumber(ctx);
QString str;
fdigits = ctx->argument(0).toInteger(ctx);
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
double v = internalValue.toNumber(ctx);
QString z = QString::number(v, 'e', int (fdigits));
fdigits = ctx->argument(0).toInteger(ctx);
Value internalValue;
- self.objectValue->defaultValue(&internalValue, NUMBER_HINT);
+ self.objectValue->defaultValue(ctx, &internalValue, NUMBER_HINT);
double v = internalValue.toNumber(ctx);
ctx->result = Value::string(ctx, QString::number(v, 'g', int (fdigits)));
struct ObjectCtor: FunctionObject
{
+ static Value create(ExecutionEngine *engine);
+
ObjectCtor(Context *scope);
virtual void construct(Context *ctx);
struct StringCtor: FunctionObject
{
+ static Value create(ExecutionEngine *engine);
+
StringCtor(Context *scope);
virtual void construct(Context *ctx);
struct NumberCtor: FunctionObject
{
+ static Value create(ExecutionEngine *engine);
+
NumberCtor(Context *scope);
virtual void construct(Context *ctx);
else
x86_patch (code, (unsigned char*)target);
}
-InstructionSelection::InstructionSelection(IR::Module *module, uchar *buffer)
- : _module(module)
+InstructionSelection::InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module, uchar *buffer)
+ : _engine(engine)
+ , _module(module)
, _function(0)
, _block(0)
, _buffer(buffer)
String *InstructionSelection::identifier(const QString &s)
{
- String *&id = _identifiers[s];
- if (! id)
- id = new String(s);
- return id;
+ return _engine->identifier(s);
}
void InstructionSelection::loadTempAddress(int reg, IR::Temp *t)
amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
loadTempAddress(AMD64_RSI, base);
amd64_mov_reg_imm(_codePtr, AMD64_RDX, identifier(*m->name));
- amd64_mov_reg_imm(_codePtr, AMD64_RCX, VM::String::get(0, *str->value));
+ amd64_mov_reg_imm(_codePtr, AMD64_RCX, VM::String::get(_engine->rootContext, *str->value));
amd64_call_code(_codePtr, __qmljs_set_property_string);
return;
} else if (IR::Temp *t = s->source->asTemp()) {
class InstructionSelection: protected IR::StmtVisitor
{
public:
- InstructionSelection(IR::Module *module, uchar *code);
+ InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module, uchar *code);
~InstructionSelection();
void operator()(IR::Function *function);
virtual void visitRet(IR::Ret *);
private:
+ VM::ExecutionEngine *_engine;
IR::Module *_module;
IR::Function *_function;
IR::BasicBlock *_block;
uchar *_codePtr;
QHash<IR::BasicBlock *, QVector<uchar *> > _patches;
QHash<IR::BasicBlock *, uchar *> _addrs;
- QHash<QString, VM::String *> _identifiers;
};
} // end of namespace x86_64