From 945c988b4526c2363d80f530770d1595062518a2 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Sun, 20 May 2012 19:59:47 +0200 Subject: [PATCH] Initial support for Array objects. --- qmljs_objects.cpp | 56 ++++++++++++++- qmljs_objects.h | 15 ++++ qmljs_runtime.cpp | 70 +++++++++++++++++- qmljs_runtime.h | 16 ++++- qv4array.cpp | 20 ++++++ qv4array_p.h | 38 +++------- qv4codegen.cpp | 18 +++-- qv4ecmaobjects.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++- qv4ecmaobjects_p.h | 32 +++++++++ qv4isel.cpp | 25 +++++-- v4.pro | 3 +- 11 files changed, 449 insertions(+), 48 deletions(-) create mode 100644 qv4array.cpp diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp index a9f445b..eb4eb44 100644 --- a/qmljs_objects.cpp +++ b/qmljs_objects.cpp @@ -102,6 +102,16 @@ bool Object::deleteProperty(String *name, bool flag) return false; } +Value *ArrayObject::getOwnProperty(String *name, PropertyAttributes *attributes) +{ + if (name->toQString() == QLatin1String("length")) { + length.numberValue = value.size(); + return &length; + } + + return Object::getOwnProperty(name, attributes); +} + bool FunctionObject::hasInstance(const Value &value) const { Q_UNUSED(value); @@ -188,28 +198,42 @@ ExecutionEngine::ExecutionEngine() rootContext = newContext(); rootContext->init(this); + objectPrototype.type = NULL_TYPE; + stringPrototype.type = NULL_TYPE; + numberPrototype.type = NULL_TYPE; + booleanPrototype.type = NULL_TYPE; + arrayPrototype.type = NULL_TYPE; + datePrototype.type = NULL_TYPE; + //functionPrototype.type = NULL_TYPE; + // // set up the global object // + String *prototype = identifier(QLatin1String("prototype")); + VM::Object *glo = newArgumentsObject(rootContext); __qmljs_init_object(&globalObject, glo); __qmljs_init_object(&rootContext->activation, glo); objectCtor = ObjectCtor::create(this); + objectCtor.objectValue->get(prototype, &objectPrototype); + stringCtor = StringCtor::create(this); numberCtor = NumberCtor::create(this); + booleanCtor = BooleanCtor::create(this); + arrayCtor = ArrayCtor::create(this); dateCtor = DateCtor::create(this); - String *prototype = identifier(QLatin1String("prototype")); - - objectCtor.objectValue->get(prototype, &objectPrototype); stringCtor.objectValue->get(prototype, &stringPrototype); numberCtor.objectValue->get(prototype, &numberPrototype); + booleanCtor.objectValue->get(prototype, &booleanPrototype); + arrayCtor.objectValue->get(prototype, &arrayPrototype); dateCtor.objectValue->get(prototype, &datePrototype); glo->put(identifier(QLatin1String("Object")), objectCtor); glo->put(identifier(QLatin1String("String")), stringCtor); glo->put(identifier(QLatin1String("Number")), numberCtor); + glo->put(identifier(QLatin1String("Array")), arrayCtor); glo->put(identifier(QLatin1String("Date")), dateCtor); glo->put(identifier(QLatin1String("Math")), Value::fromObject(newMathObject(rootContext))); } @@ -308,6 +332,32 @@ Object *ExecutionEngine::newBooleanPrototype(Context *ctx, FunctionObject *proto return booleanProto; } +Object *ExecutionEngine::newArrayObject() +{ + ArrayObject *object = new ArrayObject(); + object->prototype = arrayPrototype.objectValue; + return object; +} + +Object *ExecutionEngine::newArrayObject(const Array &value) +{ + ArrayObject *object = new ArrayObject(value); + object->prototype = arrayPrototype.objectValue; + return object; +} + +FunctionObject *ExecutionEngine::newArrayCtor(Context *ctx) +{ + return new ArrayCtor(ctx); +} + +Object *ExecutionEngine::newArrayPrototype(Context *ctx, FunctionObject *proto) +{ + Object *arrayProto = new ArrayPrototype(ctx, proto); + arrayProto->prototype = objectPrototype.objectValue; + return arrayProto; +} + Object *ExecutionEngine::newDateObject(const Value &value) { return new DateObject(value); diff --git a/qmljs_objects.h b/qmljs_objects.h index 3a06e7e..60829d2 100644 --- a/qmljs_objects.h +++ b/qmljs_objects.h @@ -2,6 +2,7 @@ #define QMLJS_OBJECTS_H #include "qmljs_runtime.h" +#include "qv4array_p.h" #include #include @@ -247,7 +248,12 @@ struct DateObject: Object { }; struct ArrayObject: Object { + Array value; + Value length; + ArrayObject() { length.type = NUMBER_TYPE; } + ArrayObject(const Array &value): value(value) { length.type = NUMBER_TYPE; } virtual ArrayObject *asArrayObject() { return this; } + virtual Value *getOwnProperty(String *name, PropertyAttributes *attributes); }; struct FunctionObject: Object { @@ -377,11 +383,15 @@ struct ExecutionEngine Value objectCtor; Value stringCtor; Value numberCtor; + Value booleanCtor; + Value arrayCtor; Value dateCtor; Value objectPrototype; Value stringPrototype; Value numberPrototype; + Value booleanPrototype; + Value arrayPrototype; Value datePrototype; QHash identifiers; @@ -412,6 +422,11 @@ struct ExecutionEngine FunctionObject *newBooleanCtor(Context *ctx); Object *newBooleanPrototype(Context *ctx, FunctionObject *proto); + Object *newArrayObject(); + Object *newArrayObject(const Array &value); + FunctionObject *newArrayCtor(Context *ctx); + Object *newArrayPrototype(Context *ctx, FunctionObject *proto); + Object *newDateObject(const Value &value); FunctionObject *newDateCtor(Context *ctx); Object *newDatePrototype(Context *ctx, FunctionObject *proto); diff --git a/qmljs_runtime.cpp b/qmljs_runtime.cpp index b83cc32..91b23ed 100644 --- a/qmljs_runtime.cpp +++ b/qmljs_runtime.cpp @@ -71,6 +71,13 @@ int Value::toInt32(double number) return (int) trunc(number); // ### } +uint Value::toUInt32(double number) +{ + if (! number || isnan(number) || isinf(number)) + return +0; + return (uint) trunc(number); // ### +} + int Value::toInteger(double number) { if (isnan(number)) @@ -344,7 +351,9 @@ void __qmljs_object_default_value(Context *ctx, Value *result, const Value *obje if (typeHint == NUMBER_HINT) qSwap(meth1, meth2); - Value *conv = object->asObject()->getProperty(meth1); + Object *oo = object->asObject(); + assert(oo != 0); + Value *conv = oo->getProperty(meth1); if (conv && conv->isFunctionObject()) { Value r; __qmljs_call_value(ctx, &r, object, conv, 0, 0); @@ -364,7 +373,7 @@ void __qmljs_object_default_value(Context *ctx, Value *result, const Value *obje } } - assert(!"type error"); + __qmljs_init_undefined(result); } void __qmljs_throw_type_error(Context *ctx, Value *result) @@ -433,6 +442,63 @@ void __qmljs_set_property_closure(Context *ctx, Value *object, String *name, IR: object->objectValue->put(name, value, /*flag*/ 0); } +void __qmljs_get_element(Context *ctx, Value *result, Value *object, Value *index) +{ + if (object->isString() && index->isNumber()) { + const QString s = object->stringValue->toQString().mid(Value::toUInt32(index->numberValue), 1); + if (s.isNull()) + __qmljs_init_undefined(result); + else + *result = Value::fromString(ctx, s); + } else if (object->isArrayObject() && index->isNumber()) { + *result = object->asArrayObject()->value.at(Value::toUInt32(index->numberValue)); + } else { + String *name = index->toString(ctx); + + if (! object->isObject()) + __qmljs_to_object(ctx, object, object); + + object->objectValue->get(name, result); + } +} + +void __qmljs_set_element(Context *ctx, Value *object, Value *index, Value *value) +{ + if (object->isArrayObject() && index->isNumber()) { + object->asArrayObject()->value.assign(Value::toUInt32(index->numberValue), *value); + } else { + String *name = index->toString(ctx); + + if (! object->isObject()) + __qmljs_to_object(ctx, object, object); + + object->objectValue->put(name, *value, /*flags*/ 0); + } +} + +void __qmljs_set_element_number(Context *ctx, Value *object, Value *index, double number) +{ + Value v; + __qmljs_init_number(&v, number); + __qmljs_set_element(ctx, object, index, &v); +} + +void __qmljs_set_activation_element(Context *ctx, String *name, Value *index, Value *value) +{ + if (Value *base = ctx->lookup(name)) { + __qmljs_set_element(ctx, base, index, value); + } else { + assert(!"reference error"); + } +} + +void __qmljs_set_activation_element_number(Context *ctx, String *name, Value *index, double number) +{ + Value v; + __qmljs_init_number(&v, number); + __qmljs_set_activation_element(ctx, name, index, &v); +} + void __qmljs_set_activation_property(Context *ctx, String *name, Value *value) { if (Value *prop = ctx->lookup(name)) { diff --git a/qmljs_runtime.h b/qmljs_runtime.h index 9837a46..cd571fd 100644 --- a/qmljs_runtime.h +++ b/qmljs_runtime.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace QQmlJS { @@ -111,6 +112,14 @@ void __qmljs_get_activation_property(Context *ctx, Value *result, String *name); void __qmljs_copy_activation_property(Context *ctx, String *name, String *other); void __qmljs_copy_property(Context *ctx, Value *target, String *name, Value *source, String *other); +void __qmljs_get_element(Context *ctx, Value *result, Value *object, Value *index); + +void __qmljs_set_element(Context *ctx, Value *object, Value *index, Value *value); +void __qmljs_set_element_number(Context *ctx, Value *object, Value *index, double number); + +void __qmljs_set_activation_element(Context *ctx, String *name, Value *index, Value *value); +void __qmljs_set_activation_element_number(Context *ctx, String *name, Value *index, double number); + // context void __qmljs_get_activation(Context *ctx, Value *result); void __qmljs_get_thisObject(Context *ctx, Value *result); @@ -222,6 +231,8 @@ struct Value { static int toInteger(double fromNumber); static int toInt32(double value); + static uint toUInt32(double value); + int toUInt16(Context *ctx); int toInt32(Context *ctx); uint toUInt32(Context *ctx); @@ -420,7 +431,10 @@ inline void __qmljs_to_string(Context *ctx, Value *result, const Value *value) case OBJECT_TYPE: { Value prim; __qmljs_to_primitive(ctx, &prim, value, STRING_HINT); - __qmljs_to_string(ctx, result, &prim); + if (prim.isPrimitive()) + __qmljs_to_string(ctx, result, &prim); + else + assert(!"type error"); break; } diff --git a/qv4array.cpp b/qv4array.cpp new file mode 100644 index 0000000..9cdd06b --- /dev/null +++ b/qv4array.cpp @@ -0,0 +1,20 @@ + +#include "qv4array_p.h" +#include "qmljs_objects.h" + +using namespace QQmlJS::VM; + +bool ArrayElementLessThan::operator()(const Value &v1, const Value &v2) const +{ + if (v1.isUndefined()) + return false; + if (v2.isUndefined()) + return true; + if (!m_comparefn.isUndefined()) { + Value args[] = { v1, v2 }; + Value result; + __qmljs_call_value(m_context, &result, 0, &m_comparefn, args, 2); + return result.toNumber(m_context) <= 0; + } + return v1.toString(m_context)->toQString() < v2.toString(m_context)->toQString(); +} diff --git a/qv4array_p.h b/qv4array_p.h index 10cb683..a80c8a6 100644 --- a/qv4array_p.h +++ b/qv4array_p.h @@ -11,7 +11,7 @@ namespace VM { class Array { public: - inline Array(ExecutionEngine *engine); + inline Array(); inline Array(const Array &other); inline ~Array(); @@ -38,7 +38,6 @@ private: MapMode }; - ExecutionEngine *m_engine; Mode m_mode; int m_instances; @@ -54,37 +53,21 @@ public: inline ArrayElementLessThan(Context *context, const Value &comparefn) : m_context(context), m_comparefn(comparefn) {} - inline bool operator()(const Value &v1, const Value &v2) const - { - if (v1.isUndefined()) - return false; - if (v2.isUndefined()) - return true; - if (!m_comparefn.isUndefined()) { - ArrayElementLessThan *that = const_cast(this); - Value args[] = { v1, v2 }; - Value result; - __qmljs_call_value(m_context, &result, 0, &m_comparefn, args, 2); - return result.toNumber(m_context) <= 0; - } - return v1.toString(m_context)->toQString() < v2.toString(m_context)->toQString(); - } + bool operator()(const Value &v1, const Value &v2) const; private: Context *m_context; Value m_comparefn; }; -inline Array::Array(ExecutionEngine *engine): - m_engine(engine), - m_mode(VectorMode), - m_instances(0) +inline Array::Array() + : m_mode(VectorMode) + , m_instances(0) { to_vector = new QVector(); } inline Array::Array(const Array &other): - m_engine(other.m_engine), m_mode(other.m_mode), m_instances(other.m_instances) { @@ -104,7 +87,6 @@ inline Array::~Array() inline Array &Array::operator = (const Array &other) { - m_engine = other.m_engine; m_instances = other.m_instances; if (m_mode != other.m_mode) { if (m_mode == VectorMode) @@ -166,8 +148,6 @@ inline void Array::assign(uint index, const Value &v) { if (index >= size()) { resize(index + 1); - // if (m_engine) - // m_engine->adjustBytesAllocated(sizeof(Value) * (size() - index)); } const Value &oldv = at(index); @@ -208,7 +188,7 @@ inline void Array::resize(uint s) if (m_mode == VectorMode) { if (s < N) { - to_vector->resize (s); + to_vector->resize (s); // ### init } else { // switch to MapMode QMap *m = new QMap(); @@ -226,7 +206,7 @@ inline void Array::resize(uint s) else { if (s < N) { // switch to VectorMode - QVector *v = new QVector (s); + QVector *v = new QVector (s, Value::undefinedValue()); QMap::const_iterator it = to_map->constBegin(); for ( ; (it != to_map->constEnd()) && (it.key() < s); ++it) (*v) [it.key()] = it.value(); @@ -259,9 +239,7 @@ inline void Array::concat(const Array &other) for (uint i = 0; i < other.size(); ++i) { Value v = other.at(i); if (! v.isUndefined()) - continue; - - assign(k + i, v); + assign(k + i, v); } } diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 6abd114..86dfe84 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -322,13 +322,19 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name) IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index) { - if (base->asTemp() || base->asName()) - return _block->SUBSCRIPT(base, index); - else { + if (! base->asTemp()) { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), base); - return _block->SUBSCRIPT(_block->TEMP(t), index); + _block->MOVE(_block->TEMP(t), base); + base = _block->TEMP(t); + } + + if (! index->asTemp()) { + const unsigned t = _block->newTemp(); + _block->MOVE(_block->TEMP(t), index); + index = _block->TEMP(t); } + + return _block->SUBSCRIPT(base, index); } IR::Expr *Codegen::argument(IR::Expr *expr) @@ -1056,7 +1062,7 @@ bool Codegen::visit(FunctionExpression *ast) bool Codegen::visit(IdentifierExpression *ast) { - if (! _function->needsActivation()) { + if (! _function->hasDirectEval) { int index = _env->findMember(ast->name.toString()); if (index != -1) { _expr.code = _block->TEMP(index); diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index c018cae..3b4890c 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -499,6 +499,12 @@ void ObjectCtor::call(Context *) ObjectPrototype::ObjectPrototype(Context *ctx, FunctionObject *ctor) { setProperty(ctx, QLatin1String("constructor"), Value::fromObject(ctor)); + setProperty(ctx, QLatin1String("toString"), method_toString, 0); +} + +void ObjectPrototype::method_toString(Context *ctx) +{ + ctx->result = Value::fromString(ctx, "object"); } // @@ -573,7 +579,11 @@ QString StringPrototype::getThisString(Context *ctx) void StringPrototype::method_toString(Context *ctx) { - __qmljs_to_string(ctx, &ctx->result, &ctx->thisObject); + if (StringObject *o = ctx->thisObject.asStringObject()) { + ctx->result = o->value; + } else { + assert(!"type error"); + } } void StringPrototype::method_valueOf(Context *ctx) @@ -1064,6 +1074,198 @@ void BooleanPrototype::method_valueOf(Context *ctx) } // +// Array object +// +// +// Number object +// +Value ArrayCtor::create(ExecutionEngine *engine) +{ + Context *ctx = engine->rootContext; + FunctionObject *ctor = ctx->engine->newArrayCtor(ctx); + ctor->setProperty(ctx, QLatin1String("prototype"), Value::fromObject(ctx->engine->newArrayPrototype(ctx, ctor))); + return Value::fromObject(ctor); +} + +ArrayCtor::ArrayCtor(Context *scope) + : FunctionObject(scope) +{ +} + +void ArrayCtor::construct(Context *ctx) +{ + ctx->thisObject = Value::fromObject(ctx->engine->newArrayObject()); +} + +void ArrayCtor::call(Context *ctx) +{ + ctx->result = Value::fromObject(ctx->engine->newArrayObject()); +} + +ArrayPrototype::ArrayPrototype(Context *ctx, FunctionObject *ctor) +{ + setProperty(ctx, QLatin1String("constructor"), Value::fromObject(ctor)); + setProperty(ctx, QLatin1String("toString"), method_toString, 0); + setProperty(ctx, QLatin1String("toLocalString"), method_toLocaleString, 0); + setProperty(ctx, QLatin1String("concat"), method_concat, 1); + setProperty(ctx, QLatin1String("join"), method_join, 1); + setProperty(ctx, QLatin1String("pop"), method_pop, 0); + setProperty(ctx, QLatin1String("push"), method_push, 1); + setProperty(ctx, QLatin1String("reverse"), method_reverse, 0); + setProperty(ctx, QLatin1String("shift"), method_shift, 0); + setProperty(ctx, QLatin1String("slice"), method_slice, 2); + setProperty(ctx, QLatin1String("sort"), method_sort, 1); + setProperty(ctx, QLatin1String("splice"), method_splice, 2); + setProperty(ctx, QLatin1String("unshift"), method_unshift, 1); +} + +void ArrayPrototype::method_toString(Context *ctx) +{ + method_join(ctx); +} + +void ArrayPrototype::method_toLocaleString(Context *ctx) +{ + method_toString(ctx); +} + +void ArrayPrototype::method_concat(Context *ctx) +{ + Array result; + + if (ArrayObject *instance = ctx->thisObject.asArrayObject()) + result = instance->value; + else { + QString v = ctx->thisObject.toString(ctx)->toQString(); + result.assign(0, Value::fromString(ctx, v)); + } + + for (uint i = 0; i < ctx->argumentCount; ++i) { + quint32 k = result.size(); + Value arg = ctx->argument(i); + + if (ArrayObject *elt = arg.asArrayObject()) + result.concat(elt->value); + + else + result.assign(k, Value::fromString(arg.toString(ctx))); + } + + ctx->result = Value::fromObject(ctx->engine->newArrayObject(result)); +} + +void ArrayPrototype::method_join(Context *ctx) +{ + Value arg = ctx->argument(0); + + QString r4; + if (arg.isUndefined()) + r4 = QLatin1String(","); + else + r4 = arg.toString(ctx)->toQString(); + + Value self = ctx->thisObject; + + Value *length = self.objectValue->getProperty(ctx->engine->identifier("length")); + double r1 = length ? length->toNumber(ctx) : 0; + quint32 r2 = Value::toUInt32(r1); + + static QSet visitedArrayElements; + + if (! r2 || visitedArrayElements.contains(self.objectValue)) { + ctx->result = Value::fromString(ctx, QString()); + return; + } + + // avoid infinite recursion + visitedArrayElements.insert(self.objectValue); + + QString R; + + if (ArrayObject *a = self.objectValue->asArrayObject()) { + for (uint i = 0; i < a->value.size(); ++i) { + if (! R.isEmpty()) + R += r4; + + Value e = a->value.at(i); + if (! (e.isUndefined() || e.isNull())) + R += e.toString(ctx)->toQString(); + } + } else { + // + // crazy! + // + Value *r6 = self.objectValue->getProperty(ctx->engine->identifier(QLatin1String("0"))); + if (r6 && !(r6->isUndefined() || r6->isNull())) + R = r6->toString(ctx)->toQString(); + + for (quint32 k = 1; k < r2; ++k) { + R += r4; + + String *name = Value::fromNumber(k).toString(ctx); + Value *r12 = self.objectValue->getProperty(name); + + if (r12 && ! (r12->isUndefined() || r12->isNull())) + R += r12->toString(ctx)->toQString(); + } + } + + visitedArrayElements.remove(self.objectValue); + ctx->result = Value::fromString(ctx, R); +} + +void ArrayPrototype::method_pop(Context *ctx) +{ + Value self = ctx->thisObject; + if (ArrayObject *instance = self.asArrayObject()) { + Value elt = instance->value.pop(); + ctx->result = elt; + } else { + String *id_length = ctx->engine->identifier(QLatin1String("length")); + Value *r1 = self.objectValue->getProperty(id_length); + quint32 r2 = r1 ? r1->toUInt32(ctx) : 0; + if (! r2) { + self.objectValue->put(id_length, Value::fromNumber(0)); + } else { + String *r6 = Value::fromNumber(r2 - 1).toString(ctx); + Value *r7 = self.objectValue->getProperty(r6); + self.objectValue->deleteProperty(r6, 0); + self.objectValue->put(id_length, Value::fromNumber(2 - 1)); + if (r7) + ctx->result = *r7; + } + } +} + +void ArrayPrototype::method_push(Context *ctx) +{ +} + +void ArrayPrototype::method_reverse(Context *ctx) +{ +} + +void ArrayPrototype::method_shift(Context *ctx) +{ +} + +void ArrayPrototype::method_slice(Context *ctx) +{ +} + +void ArrayPrototype::method_sort(Context *ctx) +{ +} + +void ArrayPrototype::method_splice(Context *ctx) +{ +} + +void ArrayPrototype::method_unshift(Context *ctx) +{ +} + +// // Date object // Value DateCtor::create(ExecutionEngine *engine) diff --git a/qv4ecmaobjects_p.h b/qv4ecmaobjects_p.h index abcf390..cb6339e 100644 --- a/qv4ecmaobjects_p.h +++ b/qv4ecmaobjects_p.h @@ -19,6 +19,9 @@ struct ObjectCtor: FunctionObject struct ObjectPrototype: Object { ObjectPrototype(Context *ctx, FunctionObject *ctor); + +protected: + static void method_toString(Context *ctx); }; struct StringCtor: FunctionObject @@ -102,6 +105,35 @@ protected: static void method_valueOf(Context *ctx); }; +struct ArrayCtor: FunctionObject +{ + static Value create(ExecutionEngine *engine); + + ArrayCtor(Context *scope); + + virtual void construct(Context *ctx); + virtual void call(Context *ctx); +}; + +struct ArrayPrototype: Object +{ + ArrayPrototype(Context *ctx, FunctionObject *ctor); + +protected: + static void method_toString(Context *ctx); + static void method_toLocaleString(Context *ctx); + static void method_concat(Context *ctx); + static void method_join(Context *ctx); + static void method_pop(Context *ctx); + static void method_push(Context *ctx); + static void method_reverse(Context *ctx); + static void method_shift(Context *ctx); + static void method_slice(Context *ctx); + static void method_sort(Context *ctx); + static void method_splice(Context *ctx); + static void method_unshift(Context *ctx); +}; + struct DateCtor: FunctionObject { static Value create(ExecutionEngine *engine); diff --git a/qv4isel.cpp b/qv4isel.cpp index 6120609..505f765 100644 --- a/qv4isel.cpp +++ b/qv4isel.cpp @@ -506,9 +506,14 @@ void InstructionSelection::visitMove(IR::Move *s) amd64_call_code(_codePtr, __qmljs_get_property); return; } - assert(!"todo"); + assert(!"wip"); + return; } else if (IR::Subscript *ss = s->source->asSubscript()) { - qWarning() << "TODO load subscript"; + amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); + loadTempAddress(AMD64_RSI, t); + loadTempAddress(AMD64_RDX, ss->base->asTemp()); + loadTempAddress(AMD64_RCX, ss->index->asTemp()); + amd64_call_code(_codePtr, __qmljs_get_element); return; } else if (IR::Unop *u = s->source->asUnop()) { if (IR::Temp *e = u->expr->asTemp()) { @@ -527,6 +532,7 @@ void InstructionSelection::visitMove(IR::Move *s) amd64_call_code(_codePtr, op); return; } else if (IR::Const *c = u->expr->asConst()) { + assert(!"wip"); return; } } else if (IR::Binop *b = s->source->asBinop()) { @@ -666,9 +672,19 @@ void InstructionSelection::visitMove(IR::Move *s) } } } else if (IR::Subscript *ss = s->target->asSubscript()) { - if (IR::Temp *t = s->source->asTemp()) { + if (IR::Temp *t2 = s->source->asTemp()) { + loadTempAddress(AMD64_RSI, ss->base->asTemp()); + loadTempAddress(AMD64_RDX, ss->index->asTemp()); + loadTempAddress(AMD64_RCX, t2); + amd64_call_code(_codePtr, __qmljs_set_element); return; } else if (IR::Const *c = s->source->asConst()) { + amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); + loadTempAddress(AMD64_RSI, ss->base->asTemp()); + loadTempAddress(AMD64_RDX, ss->index->asTemp()); + amd64_mov_reg_imm(_codePtr, AMD64_RAX, &c->value); + amd64_movsd_reg_regp(_codePtr, X86_XMM0, AMD64_RAX); + amd64_call_code(_codePtr, __qmljs_set_element_number); return; } } @@ -704,7 +720,8 @@ void InstructionSelection::visitMove(IR::Move *s) } else if (IR::Temp *t2 = s->source->asTemp()) { amd64_mov_reg_reg(_codePtr, AMD64_RDI, AMD64_R14, 8); loadTempAddress(AMD64_RSI, t); - loadTempAddress(AMD64_RDX, t); + amd64_mov_reg_reg(_codePtr, AMD64_RDX, AMD64_RSI, 8); + // loadTempAddress(AMD64_RDX, t); loadTempAddress(AMD64_RCX, t2); void (*op)(Context *, Value *, const Value *, const Value *); switch (s->op) { diff --git a/v4.pro b/v4.pro index 2991698..4198533 100644 --- a/v4.pro +++ b/v4.pro @@ -14,7 +14,8 @@ SOURCES += main.cpp \ qmljs_objects.cpp \ qv4isel.cpp \ qv4syntaxchecker.cpp \ - qv4ecmaobjects.cpp + qv4ecmaobjects.cpp \ + qv4array.cpp HEADERS += \ qv4codegen_p.h \ -- 2.7.4