}
};
+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
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)));
}
}
{
__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)
function->code(ctx);
}
+void ScriptFunction::construct(VM::Context *ctx)
+{
+ function->code(ctx);
+}
+
Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes)
{
if (context) {
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;
virtual ~ScriptFunction();
virtual void call(Context *ctx);
+ virtual void construct(Context *ctx);
};
struct ErrorObject: Object {
Value result;
String **formals;
size_t formalCount;
+ bool calledAsConstructor;
inline Value argument(size_t index = 0)
{
result.type = UNDEFINED_TYPE;
formals = 0;
formalCount = 0;
+ calledAsConstructor = false;
}
};
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 {
_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);
}
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()) {
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()) {
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;
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 *);
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)