aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoberto Raggi <roberto.raggi@nokia.com>2012-05-10 12:14:20 +0200
committerRoberto Raggi <roberto.raggi@nokia.com>2012-05-10 12:14:20 +0200
commit14ce5bb3897d0c19beddcf4b0bdabc8a05e310f0 (patch)
tree07e82e42ea4a954e8e26e88e4b276c52881f0f0b
parentc75421ee43f22df8c2405302e6118548c97f13bc (diff)
Fix constructors and some work on the String prototype.
-rw-r--r--main.cpp41
-rw-r--r--qmljs_objects.cpp10
-rw-r--r--qmljs_objects.h11
-rw-r--r--qmljs_runtime.cpp8
-rw-r--r--qv4codegen.cpp7
-rw-r--r--qv4isel.cpp55
-rw-r--r--qv4isel_p.h1
-rw-r--r--tests/string.1.js8
8 files changed, 127 insertions, 14 deletions
diff --git a/main.cpp b/main.cpp
index ef5d6eb520..8077479a4f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -73,6 +73,30 @@ struct StringCtor: FunctionObject
}
};
+struct StringPrototype: Object
+{
+ StringPrototype(Context *ctx, FunctionObject *ctor)
+ {
+ setProperty(ctx, QLatin1String("constructor"), Value::object(ctx, ctor));
+ setProperty(ctx, QLatin1String("toString"), toString);
+ }
+
+ void setProperty(Context *ctx, const QString &name, const Value &value)
+ {
+ put(String::get(ctx, name), value);
+ }
+
+ void setProperty(Context *ctx, const QString &name, void (*code)(Context *))
+ {
+ setProperty(ctx, name, Value::object(ctx, new NativeFunction(code)));
+ }
+
+ static void toString(Context *ctx)
+ {
+ __qmljs_to_string(ctx, &ctx->result, &ctx->thisObject);
+ }
+};
+
} // builtins
@@ -116,20 +140,25 @@ void evaluate(QQmlJS::Engine *engine, const QString &fileName, const QString &co
VM::Context *ctx = new VM::Context;
ctx->init();
- ctx->activation = VM::Value::object(ctx, new VM::ArgumentsObject(ctx));
- ctx->activation.objectValue->put(VM::String::get(ctx, QLatin1String("print")),
+ 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")),
VM::Value::object(ctx, new builtins::Print()));
- ctx->activation.objectValue->put(VM::String::get(ctx, QLatin1String("Object")),
+ globalObject->put(VM::String::get(ctx, QLatin1String("Object")),
VM::Value::object(ctx, new builtins::ObjectCtor()));
- ctx->activation.objectValue->put(VM::String::get(ctx, QLatin1String("String")),
- VM::Value::object(ctx, new builtins::StringCtor()));
+ VM::FunctionObject *stringCtor = new builtins::StringCtor();
+ stringCtor->put(prototype, VM::Value::object(ctx, new builtins::StringPrototype(ctx, stringCtor)));
+ globalObject->put(VM::String::get(ctx, QLatin1String("String")), VM::Value::object(ctx, stringCtor));
foreach (IR::Function *function, module.functions) {
if (function->name && ! function->name->isEmpty()) {
- ctx->activation.objectValue->put(VM::String::get(ctx, *function->name),
+ globalObject->put(VM::String::get(ctx, *function->name),
VM::Value::object(ctx, new VM::ScriptFunction(ctx, function)));
}
}
diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp
index 7f4b8553cd..7a373516f8 100644
--- a/qmljs_objects.cpp
+++ b/qmljs_objects.cpp
@@ -116,11 +116,6 @@ void FunctionObject::construct(Context *ctx)
{
__qmljs_init_object(ctx, &ctx->thisObject, new Object());
call(ctx);
- Value proto;
- if (get(String::get(ctx, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
- if (proto.type == OBJECT_TYPE)
- ctx->thisObject.objectValue->prototype = proto.objectValue;
- }
}
ScriptFunction::ScriptFunction(Context *context, IR::Function *function)
@@ -146,6 +141,11 @@ void ScriptFunction::call(VM::Context *ctx)
function->code(ctx);
}
+void ScriptFunction::construct(VM::Context *ctx)
+{
+ function->code(ctx);
+}
+
Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes)
{
if (context) {
diff --git a/qmljs_objects.h b/qmljs_objects.h
index dbb1ab8d8b..323367a9a8 100644
--- a/qmljs_objects.h
+++ b/qmljs_objects.h
@@ -245,6 +245,14 @@ struct FunctionObject: Object {
virtual void construct(Context *ctx);
};
+struct NativeFunction: FunctionObject {
+ void (*code)(Context *);
+
+ NativeFunction(void (*code)(Context *)): code(code) {}
+ virtual void call(Context *ctx) { code(ctx); }
+ virtual void construct(Context *ctx) { code(ctx); }
+};
+
struct ScriptFunction: FunctionObject {
Context *context;
IR::Function *function;
@@ -253,6 +261,7 @@ struct ScriptFunction: FunctionObject {
virtual ~ScriptFunction();
virtual void call(Context *ctx);
+ virtual void construct(Context *ctx);
};
struct ErrorObject: Object {
@@ -276,6 +285,7 @@ struct Context {
Value result;
String **formals;
size_t formalCount;
+ bool calledAsConstructor;
inline Value argument(size_t index = 0)
{
@@ -303,6 +313,7 @@ struct Context {
result.type = UNDEFINED_TYPE;
formals = 0;
formalCount = 0;
+ calledAsConstructor = false;
}
};
diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp
index 3486a65500..b0a3c100ea 100644
--- a/qmljs_runtime.cpp
+++ b/qmljs_runtime.cpp
@@ -445,7 +445,15 @@ void __qmljs_construct_property(Context *context, Value *result, Value *base, St
context->thisObject = thisObject;
context->formals = f->formalParameterList;
context->formalCount = f->formalParameterCount;
+ context->calledAsConstructor = true;
f->construct(context);
+
+ Value proto;
+ if (f->get(String::get(context, QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
+ if (proto.type == OBJECT_TYPE)
+ context->thisObject.objectValue->prototype = proto.objectValue;
+ }
+
if (result)
__qmljs_copy(result, &context->thisObject);
} else {
diff --git a/qv4codegen.cpp b/qv4codegen.cpp
index 369d7e77a2..2bc9dbd8f2 100644
--- a/qv4codegen.cpp
+++ b/qv4codegen.cpp
@@ -300,6 +300,13 @@ void Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op)
_block->MOVE(target, _block->TEMP(t), op);
return;
}
+ } else if (! target->asTemp()) {
+ if (! (source->asConst() || source->asTemp() || source->asName() || source->asSubscript())) {
+ const unsigned t = _block->newTemp();
+ _block->MOVE(_block->TEMP(t), source);
+ _block->MOVE(target, _block->TEMP(t), op);
+ return;
+ }
}
_block->MOVE(target, source, op);
}
diff --git a/qv4isel.cpp b/qv4isel.cpp
index 35a770683e..a689bec753 100644
--- a/qv4isel.cpp
+++ b/qv4isel.cpp
@@ -330,6 +330,49 @@ void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *
amd64_call_code(_codePtr, __qmljs_dispose_context);
}
+void InstructionSelection::constructProperty(IR::New *ctor, IR::Temp *result)
+{
+ IR::Member *member = ctor->base->asMember();
+ assert(member != 0);
+ assert(member->base->asTemp());
+
+ int argc = 0;
+ for (IR::ExprList *it = ctor->args; it; it = it->next)
+ ++argc;
+
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
+ amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+ amd64_mov_reg_imm(_codePtr, AMD64_RDX, argc);
+ amd64_call_code(_codePtr, __qmljs_new_context);
+
+ amd64_mov_reg_reg(_codePtr, AMD64_R15, AMD64_RAX, 8);
+
+ argc = 0;
+ for (IR::ExprList *it = ctor->args; it; it = it->next) {
+ IR::Temp *t = it->expr->asTemp();
+ Q_ASSERT(t != 0);
+ amd64_mov_reg_membase(_codePtr, AMD64_RAX, AMD64_R15, offsetof(Context, arguments), 8);
+ amd64_lea_membase(_codePtr, AMD64_RDI, AMD64_RAX, argc * sizeof(Value));
+ loadTempAddress(AMD64_RSI, t);
+ amd64_call_code(_codePtr, __qmljs_copy);
+ ++argc;
+ }
+
+ // __qmljs_construct_property(Context *context, Value *result, Value *base, String *name)
+
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ if (result)
+ loadTempAddress(AMD64_RSI, result);
+ else
+ amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_RSI, AMD64_RSI);
+ loadTempAddress(AMD64_RDX, member->base->asTemp());
+ amd64_mov_reg_imm(_codePtr, AMD64_RCX, identifier(*member->name));
+ amd64_call_code(_codePtr, __qmljs_construct_property);
+
+ amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+ amd64_call_code(_codePtr, __qmljs_dispose_context);
+}
+
void InstructionSelection::visitExp(IR::Exp *s)
{
if (IR::Call *c = s->expr->asCall()) {
@@ -475,8 +518,13 @@ void InstructionSelection::visitMove(IR::Move *s)
amd64_call_code(_codePtr, __qmljs_init_closure);
return;
} else if (IR::New *ctor = s->source->asNew()) {
- constructActivationProperty(ctor, t);
- return;
+ if (ctor->base->asName()) {
+ constructActivationProperty(ctor, t);
+ return;
+ } else if (ctor->base->asMember()) {
+ constructProperty(ctor, t);
+ return;
+ }
} else if (IR::Member *m = s->source->asMember()) {
//__qmljs_get_property(ctx, result, object, name);
if (IR::Temp *base = m->base->asTemp()) {
@@ -600,6 +648,9 @@ void InstructionSelection::visitMove(IR::Move *s)
if (c->base->asName()) {
callActivationProperty(c, t);
return;
+ } else if (c->base->asMember()) {
+ callProperty(c, t);
+ return;
} else if (c->base->asTemp()) {
callValue(c, t);
return;
diff --git a/qv4isel_p.h b/qv4isel_p.h
index 77bf4bbca9..a52b291e9f 100644
--- a/qv4isel_p.h
+++ b/qv4isel_p.h
@@ -24,6 +24,7 @@ protected:
void callActivationProperty(IR::Call *call, IR::Temp *result);
void callProperty(IR::Call *call, IR::Temp *result);
void constructActivationProperty(IR::New *call, IR::Temp *result);
+ void constructProperty(IR::New *ctor, IR::Temp *result);
void callValue(IR::Call *call, IR::Temp *result);
virtual void visitExp(IR::Exp *);
diff --git a/tests/string.1.js b/tests/string.1.js
index 1495552e33..5ae5535881 100644
--- a/tests/string.1.js
+++ b/tests/string.1.js
@@ -3,5 +3,11 @@ var s = String(123) + 1
print(s)
var s2 = new String(123)
-print(s2)
+print(s2, s2.toString, s2.toString())
+
+var s3 = String.prototype.constructor(321)
+print(s3)
+
+var s4 = new String.prototype.constructor(321)
+print(s4)