Bind the `this' object.

This commit is contained in:
Roberto Raggi 2012-05-09 12:00:30 +02:00
parent 80af77292e
commit 63e50c2e1c
5 changed files with 85 additions and 7 deletions

View File

@ -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);

View 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);

View 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);

View 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 *);

10
tests/obj.2.js Normal file
View File

@ -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()