From 63e50c2e1cbbbfa86e24425e1b640d67d1ade845 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Wed, 9 May 2012 12:00:30 +0200 Subject: [PATCH] Bind the `this' object. --- qmljs_runtime.cpp | 13 ++++++++- qmljs_runtime.h | 1 + qv4isel.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++----- qv4isel_p.h | 1 + tests/obj.2.js | 10 +++++++ 5 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 tests/obj.2.js diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index bdc4d98ed0..0b8eca8052 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -367,11 +367,22 @@ 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); diff --git a/qmljs_runtime.h b/qmljs_runtime.h index 70a5782458..d2e72bc241 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -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); diff --git a/qv4isel.cpp b/qv4isel.cpp index 72a4bdbd3b..11340250c3 100644 --- a/qv4isel.cpp +++ b/qv4isel.cpp @@ -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); diff --git a/qv4isel_p.h b/qv4isel_p.h index 360fc38e6c..e06b39c981 100644 --- a/qv4isel_p.h +++ b/qv4isel_p.h @@ -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 index 0000000000..e9b1be5be0 --- /dev/null +++ b/tests/obj.2.js @@ -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()