diff options
author | Roberto Raggi <roberto.raggi@nokia.com> | 2012-05-10 12:14:20 +0200 |
---|---|---|
committer | Roberto Raggi <roberto.raggi@nokia.com> | 2012-05-10 12:14:20 +0200 |
commit | 14ce5bb3897d0c19beddcf4b0bdabc8a05e310f0 (patch) | |
tree | 07e82e42ea4a954e8e26e88e4b276c52881f0f0b | |
parent | c75421ee43f22df8c2405302e6118548c97f13bc (diff) |
Fix constructors and some work on the String prototype.
-rw-r--r-- | main.cpp | 41 | ||||
-rw-r--r-- | qmljs_objects.cpp | 10 | ||||
-rw-r--r-- | qmljs_objects.h | 11 | ||||
-rw-r--r-- | qmljs_runtime.cpp | 8 | ||||
-rw-r--r-- | qv4codegen.cpp | 7 | ||||
-rw-r--r-- | qv4isel.cpp | 55 | ||||
-rw-r--r-- | qv4isel_p.h | 1 | ||||
-rw-r--r-- | tests/string.1.js | 8 |
8 files changed, 127 insertions, 14 deletions
@@ -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) |