Initial support for Array objects.
authorRoberto Raggi <roberto.raggi@nokia.com>
Sun, 20 May 2012 17:59:47 +0000 (19:59 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Mon, 21 May 2012 07:52:55 +0000 (09:52 +0200)
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4array.cpp [new file with mode: 0644]
qv4array_p.h
qv4codegen.cpp
qv4ecmaobjects.cpp
qv4ecmaobjects_p.h
qv4isel.cpp
v4.pro

index a9f445b..eb4eb44 100644 (file)
@@ -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);
index 3a06e7e..60829d2 100644 (file)
@@ -2,6 +2,7 @@
 #define QMLJS_OBJECTS_H
 
 #include "qmljs_runtime.h"
+#include "qv4array_p.h"
 
 #include <QtCore/QString>
 #include <QtCore/QHash>
@@ -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<QString, String *> 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);
index b83cc32..91b23ed 100644 (file)
@@ -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)) {
index 9837a46..cd571fd 100644 (file)
@@ -4,6 +4,7 @@
 #include <QtCore/QString>
 #include <QtCore/QDebug>
 #include <math.h>
+#include <cassert>
 
 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 (file)
index 0000000..9cdd06b
--- /dev/null
@@ -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();
+}
index 10cb683..a80c8a6 100644 (file)
@@ -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<ArrayElementLessThan*>(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<Value>();
 }
 
 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<uint, Value> *m = new QMap<uint, Value>();
@@ -226,7 +206,7 @@ inline void Array::resize(uint s)
     else {
         if (s < N) {
             // switch to VectorMode
-            QVector<Value> *v = new QVector<Value> (s);
+            QVector<Value> *v = new QVector<Value> (s, Value::undefinedValue());
             QMap<uint, Value>::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);
     }
 }
 
index 6abd114..86dfe84 100644 (file)
@@ -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);
index c018cae..3b4890c 100644 (file)
@@ -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<Object *> 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)
index abcf390..cb6339e 100644 (file)
@@ -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);
index 6120609..505f765 100644 (file)
@@ -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 (file)
--- 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 \