Bind the `this' object.
authorRoberto Raggi <roberto.raggi@nokia.com>
Wed, 9 May 2012 10:00:30 +0000 (12:00 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Wed, 9 May 2012 10:01:16 +0000 (12:01 +0200)
qmljs_runtime.cpp
qmljs_runtime.h
qv4isel.cpp
qv4isel_p.h
tests/obj.2.js [new file with mode: 0644]

index bdc4d98..0b8eca8 100644 (file)
@@ -368,10 +368,21 @@ void __qmljs_dispose_context(Context *ctx)
 
 void __qmljs_call_activation_property(Context *context, Value *result, String *name)
 {
+    __qmljs_call_property(context, result, &context->parent->activation, name);
+}
+
+void __qmljs_call_property(Context *context, Value *result, Value *base, String *name)
+{
     Value func;
-    context->parent->activation.objectValue->get(name, &func);
+    Value thisObject = *base;
+    if (thisObject.type != OBJECT_TYPE)
+        __qmljs_to_object(context, &thisObject, base);
+
+    assert(thisObject.type == OBJECT_TYPE);
+    thisObject.objectValue->get(name, &func);
     if (func.type == OBJECT_TYPE) {
         if (FunctionObject *f = func.objectValue->asFunctionObject()) {
+            context->thisObject = thisObject;
             context->formals = f->formalParameterList;
             context->formalCount = f->formalParameterCount;
             f->call(context);
index 70a5782..d2e72bc 100644 (file)
@@ -48,6 +48,7 @@ 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);
+void __qmljs_call_property(Context *context, Value *result, Value *base, String *name);
 
 // constructors
 void __qmljs_init_undefined(Context *ctx, Value *result);
index 72a4bdb..1134025 100644 (file)
@@ -170,6 +170,9 @@ void InstructionSelection::loadTempAddress(int reg, IR::Temp *t)
 
 void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *result)
 {
+    IR::Name *baseName = call->base->asName();
+    assert(baseName != 0);
+
     int argc = 0;
     for (IR::ExprList *it = call->args; it; it = it->next)
         ++argc;
@@ -192,7 +195,7 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
         ++argc;
     }
 
-    String *id = identifier(*call->base->asName()->id);
+    String *id = identifier(*baseName->id);
     amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
     if (result)
         loadTempAddress(AMD64_RSI, result);
@@ -204,6 +207,49 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
     amd64_call_code(_codePtr, __qmljs_dispose_context);
 }
 
+void InstructionSelection::callProperty(IR::Call *call, IR::Temp *result)
+{
+    IR::Member *member = call->base->asMember();
+    assert(member != 0);
+    assert(member->base->asTemp());
+
+    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;
+    }
+
+    // __qmljs_call_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_call_property);
+
+    amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R15, 8);
+    amd64_call_code(_codePtr, __qmljs_dispose_context);
+}
+
 void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *result)
 {
     int argc = 0;
@@ -243,8 +289,13 @@ void InstructionSelection::constructActivationProperty(IR::New *call, IR::Temp *
 void InstructionSelection::visitExp(IR::Exp *s)
 {
     if (IR::Call *c = s->expr->asCall()) {
-        callActivationProperty(c, 0);
-        return;
+        if (c->base->asName()) {
+            callActivationProperty(c, 0);
+            return;
+        } else if (c->base->asMember()) {
+            callProperty(c, 0);
+            return;
+        }
     }
     Q_UNIMPLEMENTED();
     assert(!"TODO");
@@ -317,11 +368,15 @@ void InstructionSelection::visitMove(IR::Move *s)
             }
         } else if (IR::Temp *t = s->target->asTemp()) {
             if (IR::Name *n = s->source->asName()) {
-                String *propertyName = identifier(*n->id);
                 amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8);
                 loadTempAddress(AMD64_RSI, t);
-                amd64_mov_reg_imm(_codePtr, AMD64_RDX, propertyName);
-                amd64_call_code(_codePtr, __qmljs_get_activation_property);
+                if (*n->id == QLatin1String("this")) { // ### `this' should be a builtin.
+                    amd64_call_code(_codePtr, __qmljs_get_thisObject);
+                } else {
+                    String *propertyName = identifier(*n->id);
+                    amd64_mov_reg_imm(_codePtr, AMD64_RDX, propertyName);
+                    amd64_call_code(_codePtr, __qmljs_get_activation_property);
+                }
                 return;
             } else if (IR::Const *c = s->source->asConst()) {
                 loadTempAddress(AMD64_RSI, t);
index 360fc38..e06b39c 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 callProperty(IR::Call *call, IR::Temp *result);
     void constructActivationProperty(IR::New *call, IR::Temp *result);
 
     virtual void visitExp(IR::Exp *);
diff --git a/tests/obj.2.js b/tests/obj.2.js
new file mode 100644 (file)
index 0000000..e9b1be5
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+var obj = {
+    x: 10,
+    y: 20,
+    dump: function() { print("hello", this.x, this.y) }
+}
+
+print(obj.x, obj.y, obj.dump)
+obj.dump()