Initial support for object literals
authorRoberto Raggi <roberto.raggi@nokia.com>
Wed, 9 May 2012 09:04:57 +0000 (11:04 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Wed, 9 May 2012 09:05:51 +0000 (11:05 +0200)
main.cpp
qmljs_runtime.cpp
qmljs_runtime.h
qv4codegen.cpp
qv4isel.cpp
qv4isel_p.h
tests/obj.1.js [new file with mode: 0644]
tests/simple2.js

index 5ca3926..d2db6c8 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -23,7 +23,9 @@ static inline bool protect(const void *addr, size_t size)
 }
 
 namespace builtins {
+
 using namespace QQmlJS::VM;
+
 struct Print: FunctionObject
 {
     virtual void call(Context *ctx)
@@ -38,6 +40,18 @@ struct Print: FunctionObject
         std::cout << std::endl;
     }
 };
+
+struct ObjectCtor: FunctionObject
+{
+    virtual void construct(Context *ctx)
+    {
+        __qmljs_init_object(ctx, &ctx->result, new Object());
+    }
+
+    virtual void call(Context *) {
+        assert(!"not here");
+    }
+};
 } // builtins
 
 
@@ -82,8 +96,13 @@ 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::Value::object(ctx, new builtins::Print()));
+
+        ctx->activation.objectValue->put(VM::String::get(ctx, QLatin1String("Object")),
+                                         VM::Value::object(ctx, new builtins::ObjectCtor()));
+
         foreach (IR::Function *function, module.functions) {
             if (function->name && ! function->name->isEmpty()) {
                 ctx->activation.objectValue->put(VM::String::get(ctx, *function->name),
index 29cb423..8dfcb82 100644 (file)
@@ -219,9 +219,14 @@ void __qmljs_set_activation_property_string(Context *ctx, String *name, String *
 
 void __qmljs_get_property(Context *ctx, Value *result, Value *object, String *name)
 {
-    Q_UNUSED(ctx);
-    Q_ASSERT(object->type == OBJECT_TYPE);
-    object->objectValue->get(name, result);
+    if (object->type == OBJECT_TYPE) {
+        object->objectValue->get(name, result);
+    } else {
+        Value o;
+        __qmljs_to_object(ctx, &o, object);
+        assert(o.type == OBJECT_TYPE);
+        __qmljs_get_property(ctx, result, &o, name);
+    }
 }
 
 void __qmljs_get_activation_property(Context *ctx, Value *result, String *name)
@@ -361,10 +366,29 @@ void __qmljs_call_activation_property(Context *context, Value *result, String *n
             if (result)
                 __qmljs_copy(result, &context->result);
         } else {
-            Q_ASSERT(!"not a function");
+            assert(!"not a function");
+        }
+    } else {
+        assert(!"not a callable object");
+    }
+}
+
+void __qmljs_construct_activation_property(Context *context, Value *result, String *name)
+{
+    Value func;
+    context->parent->activation.objectValue->get(name, &func);
+    if (func.type == OBJECT_TYPE) {
+        if (FunctionObject *f = func.objectValue->asFunctionObject()) {
+            context->formals = f->formalParameterList;
+            context->formalCount = f->formalParameterCount;
+            f->construct(context);
+            if (result)
+                __qmljs_copy(result, &context->result);
+        } else {
+            assert(!"not a function");
         }
     } else {
-        Q_ASSERT(!"not a callable object");
+        assert(!"not a callable object");
     }
 }
 
index 438206b..61aa230 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
 Context *__qmljs_new_context(Context *current, Value *thisObject, size_t argc);
 void __qmljs_dispose_context(Context *ctx);
 void __qmljs_call_activation_property(Context *, Value *result, String *name);
+void __qmljs_construct_activation_property(Context *, Value *result, String *name);
 
 // constructors
 void __qmljs_init_undefined(Context *ctx, Value *result);
index f350dfb..a53b785 100644 (file)
@@ -244,7 +244,7 @@ void Codegen::operator()(AST::Program *node, IR::Module *module)
 
 IR::Expr *Codegen::member(IR::Expr *base, const QString *name)
 {
-    if (base->asTemp() || base->asName())
+    if (base->asTemp() /*|| base->asName()*/)
         return _block->MEMBER(base, name);
     else {
         const unsigned t = _block->newTemp();
index 1cb3bc3..4fb6ca0 100644 (file)
@@ -204,6 +204,42 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
     amd64_call_code(_codePtr, __qmljs_dispose_context);
 }
 
+void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
+{
+    int argc = 0;
+    for (IR::ExprList *it = call->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 = call->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;
+    }
+
+    String *id = identifier(*call->base->asName()->id);
+    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);
+    amd64_mov_reg_imm(_codePtr, AMD64_RDX, id);
+    amd64_call_code(_codePtr, __qmljs_construct_activation_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()) {
@@ -321,6 +357,20 @@ void InstructionSelection::visitMove(IR::Move *s)
                 amd64_mov_reg_imm(_codePtr, AMD64_RDX, new String(*str->value));
                 amd64_call_code(_codePtr, __qmljs_init_string);
                 return;
+            } else if (IR::New *ctor = s->source->asNew()) {
+                constructActivationProperty(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()) {
+                    amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
+                    loadTempAddress(AMD64_RSI, t);
+                    loadTempAddress(AMD64_RDX, base);
+                    amd64_mov_reg_imm(_codePtr, AMD64_RCX, identifier(*m->name));
+                    amd64_call_code(_codePtr, __qmljs_get_property);
+                    return;
+                }
+                assert(!"todo");
             } else if (IR::Unop *u = s->source->asUnop()) {
                 if (IR::Temp *e = u->expr->asTemp()) {
                     amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
@@ -435,6 +485,25 @@ void InstructionSelection::visitMove(IR::Move *s)
                     return;
                 }
             }
+        } else if (IR::Member *m = s->target->asMember()) {
+            if (IR::Temp *base = m->base->asTemp()) {
+                if (IR::Const *c = s->source->asConst()) {
+                    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_RAX, &c->value);
+                    amd64_movsd_reg_regp(_codePtr, X86_XMM0, AMD64_RAX);
+                    amd64_call_code(_codePtr, __qmljs_set_property_number);
+                    return;
+                } else if (IR::String *str = s->source->asString()) {
+                    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_call_code(_codePtr, __qmljs_set_property_string);
+                    return;
+                }
+            }
         }
     } else {
         // inplace assignment, e.g. x += 1, ++x, ...
@@ -472,7 +541,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
         amd64_call_code(_codePtr, __qmljs_to_boolean);
 
         amd64_patch(label2, _codePtr);
-        amd64_alu_reg_imm_size(_codePtr, X86_CMP, X86_EAX, 0, 4);
+        amd64_alu_reg_imm_size(_codePtr, X86_CMP, AMD64_RAX, 0, 4);
         _patches[s->iftrue].append(_codePtr);
         amd64_branch32(_codePtr, X86_CC_NZ, 0, 1);
 
index 753da04..360fc38 100644 (file)
@@ -22,6 +22,7 @@ protected:
     int tempOffset(IR::Temp *t);
     void loadTempAddress(int reg, IR::Temp *t);
     void callActivationProperty(IR::Call *call, IR::Temp *result);
+    void constructActivationProperty(IR::New *call, IR::Temp *result);
 
     virtual void visitExp(IR::Exp *);
     virtual void visitEnter(IR::Enter *);
diff --git a/tests/obj.1.js b/tests/obj.1.js
new file mode 100644 (file)
index 0000000..de2bd63
--- /dev/null
@@ -0,0 +1,8 @@
+
+var point = { x: 123, y: 321 }
+print(point, point.x, point.y)
+
+var obj = {}
+obj.x = 123
+obj.str = "ciao"
+print(obj, obj.str, obj.x)
index 484d1fe..4a9f966 100644 (file)
@@ -6,7 +6,7 @@ function main()
     var c = 10
     var d = 100
 
-    for (i = 0; i < 1000000; i = i + 1) {
+    for (var i = 0; i < 1000000; i = i + 1) {
         if (a == 1)
             d = d + a + b * c
         else