Add support for more sequence types
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8qobjectwrapper.cpp
index 348b6c0..40cb021 100644 (file)
 #include <QtCore/qtimer.h>
 #include <QtCore/qatomic.h>
 
-QT_BEGIN_NAMESPACE
-
 Q_DECLARE_METATYPE(QJSValue);
 Q_DECLARE_METATYPE(QDeclarativeV8Handle);
 
+QT_BEGIN_NAMESPACE
+
 #if defined(__GNUC__)
 # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
 // The code in this file does not violate strict aliasing, but GCC thinks it does
@@ -120,6 +120,17 @@ public:
 };
 
 namespace {
+
+template<typename A, typename B, typename C, typename D, typename E>
+class MaxSizeOf5 {
+    template<typename Z, typename X>
+    struct SMax {
+        static const size_t Size = sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X);
+    };
+public:
+    static const size_t Size = SMax<A, SMax<B, SMax<C, SMax<D, E> > > >::Size;
+};
+
 struct MetaCallArgument {
     inline MetaCallArgument();
     inline ~MetaCallArgument();
@@ -141,7 +152,12 @@ private:
         bool boolValue;
         QObject *qobjectPtr;
 
-        char allocData[sizeof(QVariant)];
+        char allocData[MaxSizeOf5<QVariant,
+                                QString,
+                                QList<QObject *>,
+                                QJSValue,
+                                QDeclarativeV8Handle>::Size];
+        qint64 q_for_alignment;
     };
 
     // Pointers to allocData
@@ -332,7 +348,7 @@ QObject *QV8QObjectWrapper::toQObject(QV8ObjectResource *r)
 
 // Load value properties
 static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, 
-                                          const QDeclarativePropertyCache::Data &property)
+                                          const QDeclarativePropertyData &property)
 {
     Q_ASSERT(!property.isFunction());
 
@@ -369,7 +385,13 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
         QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
         if (valueType)
             return engine->newValueType(object, property.coreIndex, valueType);
-    } 
+    } else {
+        // see if it's a sequence type
+        bool succeeded = false;
+        v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &succeeded);
+        if (succeeded)
+            return retn;
+    }
 
     QVariant var = object->metaObject()->property(property.coreIndex).read(object);
     return engine->fromVariant(var);
@@ -378,7 +400,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
 }
 
 static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *object, 
-                                                const QDeclarativePropertyCache::Data &property)
+                                                const QDeclarativePropertyData &property)
 {
     Q_ASSERT(!property.isFunction());
 
@@ -409,13 +431,18 @@ static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *obje
         void *args[] = { &handle, 0 };
         object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args); 
         return handle.toHandle();
-    } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)
-               && engine->engine()) {
+    } else if (engine->engine() && QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) {
         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
         QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
         if (valueType)
             return engine->newValueType(object, property.coreIndex, valueType);
-    } 
+    } else {
+        // see if it's a sequence type
+        bool success = false;
+        v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &success);
+        if (success)
+            return retn;
+    }
 
     QVariant var = object->metaObject()->property(property.coreIndex).read(object);
     return engine->fromVariant(var);
@@ -462,8 +489,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
         }
     }
 
-    QDeclarativePropertyCache::Data local;
-    QDeclarativePropertyCache::Data *result = 0;
+    QDeclarativePropertyData local;
+    QDeclarativePropertyData *result = 0;
     {
         QDeclarativeData *ddata = QDeclarativeData::get(object, false);
         if (ddata && ddata->propertyCache)
@@ -506,6 +533,9 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
             ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
     }
 
+    if (result->isVMEProperty())
+        return static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject*>(object->metaObject()))->vmeProperty(result->coreIndex);
+
     if (result->isDirect())  {
         return LoadPropertyDirect(engine, object, *result);
     } else {
@@ -514,7 +544,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
 }
 
 // Setter for writable properties.  Shared between the interceptor and fast property accessor
-static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyCache::Data *property,
+static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyData *property,
                                  v8::Handle<v8::Value> value)
 {
     QDeclarativeBinding *newBinding = 0;
@@ -530,10 +560,9 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativ
         int lineNumber = frame->GetLineNumber();
         QString url = engine->toString(frame->GetScriptName());
 
-        QDeclarativePropertyCache::ValueTypeData valueTypeData;
         newBinding = new QDeclarativeBinding(&function, object, context);
         newBinding->setSourceLocation(url, lineNumber);
-        newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, valueTypeData, object, context));
+        newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, object, context));
         newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
     }
 
@@ -573,6 +602,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativ
         PROPERTY_STORE(double, double(value->ToNumber()->Value()));
     } else if (property->propType == QMetaType::QString && value->IsString()) {
         PROPERTY_STORE(QString, engine->toString(value->ToString()));
+    } else if (property->isVMEProperty()) {
+        static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(object->metaObject()))->setVMEProperty(property->coreIndex, value);
     } else {
         QVariant v;
         if (property->isQList()) 
@@ -581,7 +612,6 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativ
             v = engine->toVariant(value, property->propType);
 
         QDeclarativeContextData *context = engine->callingContext();
-
         if (!QDeclarativePropertyPrivate::write(object, *property, v, context)) {
             const char *valueType = 0;
             if (v.userType() == QVariant::Invalid) valueType = "null";
@@ -603,8 +633,8 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH
         engine->qobjectWrapper()->m_destroyString == property)
         return true;
 
-    QDeclarativePropertyCache::Data local;
-    QDeclarativePropertyCache::Data *result = 0;
+    QDeclarativePropertyData local;
+    QDeclarativePropertyData *result = 0;
     result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
 
     if (!result)
@@ -710,8 +740,8 @@ v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
 
     QHashedV8String propertystring(property);
 
-    QDeclarativePropertyCache::Data local;
-    QDeclarativePropertyCache::Data *result = 0;
+    QDeclarativePropertyData local;
+    QDeclarativePropertyData *result = 0;
     result = QDeclarativePropertyCache::property(engine->engine(), object, propertystring, local);
 
     if (!result)
@@ -791,7 +821,7 @@ static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
     Q_ASSERT(ddata);
     Q_ASSERT(ddata->propertyCache);
 
-    QDeclarativePropertyCache::Data *pdata = ddata->propertyCache->property(index);
+    QDeclarativePropertyData *pdata = ddata->propertyCache->property(index);
     Q_ASSERT(pdata);
 
     Q_ASSERT(pdata->isWritable() || pdata->isQList());
@@ -845,6 +875,7 @@ static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *
 v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
 {
     Q_ASSERT(object);
+    Q_ASSERT(this->engine);
 
     Q_ASSERT(QDeclarativeData::get(object, false));
     Q_ASSERT(QDeclarativeData::get(object, false)->propertyCache == this);
@@ -860,7 +891,7 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
         // performance, but the  cost of setting up this structure hasn't been measured so 
         // its not guarenteed that this is a win overall.  We need to try and measure the cost.
         for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
-            Data *property = *iter;
+            QDeclarativePropertyData *property = *iter;
             if (property->isFunction() || 
                 property->coreIndex >= 0x7FFF || property->notifyIndex >= 0x0FFF || 
                 property->coreIndex == 0)
@@ -922,6 +953,8 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8
             ft->InstanceTemplate()->SetHasExternalResource(true);
             constructor = qPersistentNew<v8::Function>(ft->GetFunction());
         }
+
+        QDeclarativeCleanup::addToEngine(this->engine);
     }
 
     v8::Local<v8::Object> result = constructor->NewInstance();
@@ -1150,20 +1183,17 @@ int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, v
 
         QList<Connection> connections = connectionList;
 
-        QMetaMethod method = data()->metaObject()->method(index);
-        Q_ASSERT(method.methodType() == QMetaMethod::Signal);
-        // XXX TODO: We should figure out a way to cache the parameter types to avoid resolving
-        // them each time.
-        QList<QByteArray> params = method.parameterTypes();
+        QVarLengthArray<int, 9> dummy;
+        int *argsTypes = QDeclarativePropertyCache::methodParameterTypes(data(), index, dummy, 0);
 
         v8::HandleScope handle_scope;
         v8::Context::Scope scope(engine->context());
 
-        QVarLengthArray<v8::Handle<v8::Value> > args(params.count());
-        int argCount = params.count();
+        int argCount = argsTypes?argsTypes[0]:0;
+        QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);
 
         for (int ii = 0; ii < argCount; ++ii) {
-            int type = QMetaType::type(params.at(ii).constData());
+            int type = argsTypes[ii + 1];
             if (type == qMetaTypeId<QVariant>()) {
                 args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
             } else {
@@ -1429,34 +1459,13 @@ static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnTy
     }
 }
 
-static int EnumType(const QMetaObject *meta, const QString &strname)
-{
-    QByteArray str = strname.toUtf8();
-    QByteArray scope;
-    QByteArray name;
-    int scopeIdx = str.lastIndexOf("::");
-    if (scopeIdx != -1) {
-        scope = str.left(scopeIdx);
-        name = str.mid(scopeIdx + 2);
-    } else { 
-        name = str;
-    }
-    for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
-        QMetaEnum m = meta->enumerator(i);
-        if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
-            return QVariant::Int;
-    }
-    return QVariant::Invalid;
-}
-
 /*!
     Returns the match score for converting \a actual to be of type \a conversionType.  A 
     zero score means "perfect match" whereas a higher score is worse.
 
     The conversion table is copied out of the QtScript callQtMethod() function.
 */
-static int MatchScore(v8::Handle<v8::Value> actual, int conversionType, 
-                      const QByteArray &conversionTypeName)
+static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
 {
     if (actual->IsNumber()) {
         switch (conversionType) {
@@ -1528,11 +1537,13 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType,
         case QMetaType::VoidStar:
         case QMetaType::QObjectStar:
             return 0;
-        default:
-            if (!conversionTypeName.endsWith('*'))
-                return 10;
-            else
+        default: {
+            const char *typeName = QMetaType::typeName(conversionType);
+            if (typeName && typeName[strlen(typeName) - 1] == '*')
                 return 0;
+            else
+                return 10;
+        }
         }
     } else if (actual->IsObject()) {
         v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
@@ -1587,33 +1598,37 @@ static QByteArray QMetaMethod_name(const QMetaMethod &m)
 /*!
 Returns the next related method, if one, or 0.
 */
-static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object, 
-                                                             const QDeclarativePropertyCache::Data *current, 
-                                                             QDeclarativePropertyCache::Data &dummy)
+static const QDeclarativePropertyData * RelatedMethod(QObject *object,
+                                                      const QDeclarativePropertyData *current,
+                                                      QDeclarativePropertyData &dummy)
 {
     QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
-    if (current->relatedIndex == -1)
+    if (!current->isOverload())
         return 0;
 
+    Q_ASSERT(!current->overrideIndexIsProperty);
+
     if (cache) {
-        return cache->method(current->relatedIndex);
+        return cache->method(current->overrideIndex);
     } else {
         const QMetaObject *mo = object->metaObject();
         int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
 
-        while (methodOffset > current->relatedIndex) {
+        while (methodOffset > current->overrideIndex) {
             mo = mo->superClass();
             methodOffset -= QMetaObject_methods(mo);
         }
 
-        QMetaMethod method = mo->method(current->relatedIndex);
+        QMetaMethod method = mo->method(current->overrideIndex);
         dummy.load(method);
         
         // Look for overloaded methods
         QByteArray methodName = QMetaMethod_name(method);
-        for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
+        for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
             if (methodName == QMetaMethod_name(mo->method(ii))) {
-                dummy.relatedIndex = ii;
+                dummy.setFlags(dummy.getFlags() | QDeclarativePropertyData::IsOverload);
+                dummy.overrideIndexIsProperty = 0;
+                dummy.overrideIndex = ii;
                 return &dummy;
             }
         }
@@ -1622,35 +1637,32 @@ static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object,
     }
 }
 
-static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data, 
+static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyData &data,
                                          QV8Engine *engine, CallArgs &callArgs)
 {
     if (data.hasArguments()) {
 
-        QMetaMethod m = object->metaObject()->method(data.coreIndex);
-        QList<QByteArray> argTypeNames = m.parameterTypes();
-        QVarLengthArray<int, 9> argTypes(argTypeNames.count());
-
-        // ### Cache
-        for (int ii = 0; ii < argTypeNames.count(); ++ii) {
-            argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
-            if (argTypes[ii] == QVariant::Invalid) 
-                argTypes[ii] = EnumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
-            if (argTypes[ii] == QVariant::Invalid) {
-                QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)));
-                v8::ThrowException(v8::Exception::Error(engine->toString(error)));
-                return v8::Handle<v8::Value>();
-            }
+        int *args = 0;
+        QVarLengthArray<int, 9> dummy;
+        QByteArray unknownTypeError;
+
+        args = QDeclarativePropertyCache::methodParameterTypes(object, data.coreIndex, dummy, 
+                                                               &unknownTypeError);
+
+        if (!args) {
+            QString typeName = QString::fromLatin1(unknownTypeError);
+            QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
+            v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+            return v8::Handle<v8::Value>();
         }
 
-        if (argTypes.count() > callArgs.Length()) {
+        if (args[0] > callArgs.Length()) {
             QString error = QLatin1String("Insufficient arguments");
             v8::ThrowException(v8::Exception::Error(engine->toString(error)));
             return v8::Handle<v8::Value>();
         }
 
-        return CallMethod(object, data.coreIndex, data.propType, argTypes.count(), 
-                          argTypes.data(), engine, callArgs);
+        return CallMethod(object, data.coreIndex, data.propType, args[0], args + 1, engine, callArgs);
 
     } else {
 
@@ -1672,25 +1684,31 @@ Resolve the overloaded method to call.  The algorithm works conceptually like th
         If two or more overloads have the same match score, call the last one.  The match
         score is constructed by adding the matchScore() result for each of the parameters.
 */
-static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyCache::Data &data, 
+static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyData &data,
                                             QV8Engine *engine, CallArgs &callArgs)
 {
     int argumentCount = callArgs.Length();
 
-    const QDeclarativePropertyCache::Data *best = 0;
+    const QDeclarativePropertyData *best = 0;
     int bestParameterScore = INT_MAX;
     int bestMatchScore = INT_MAX;
 
-    QDeclarativePropertyCache::Data dummy;
-    const QDeclarativePropertyCache::Data *attempt = &data;
+    QDeclarativePropertyData dummy;
+    const QDeclarativePropertyData *attempt = &data;
 
     do {
-        QList<QByteArray> methodArgTypeNames;
-
-        if (attempt->hasArguments())
-            methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes();
+        QVarLengthArray<int, 9> dummy;
+        int methodArgumentCount = 0;
+        int *methodArgTypes = 0;
+        if (attempt->hasArguments()) {
+            typedef QDeclarativePropertyCache PC;
+            int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0);
+            if (!args) // Must be an unknown argument
+                continue;
 
-        int methodArgumentCount = methodArgTypeNames.count();
+            methodArgumentCount = args[0];
+            methodArgTypes = args + 1;
+        }
 
         if (methodArgumentCount > argumentCount)
             continue; // We don't have sufficient arguments to call this method
@@ -1700,22 +1718,8 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativeP
             continue; // We already have a better option
 
         int methodMatchScore = 0;
-        QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
-
-        bool unknownArgument = false;
-        for (int ii = 0; ii < methodArgumentCount; ++ii) {
-            methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
-            if (methodArgTypes[ii] == QVariant::Invalid) 
-                methodArgTypes[ii] = EnumType(object->metaObject(), 
-                                              QString::fromLatin1(methodArgTypeNames.at(ii)));
-            if (methodArgTypes[ii] == QVariant::Invalid) {
-                unknownArgument = true;
-                break;
-            }
-            methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii], methodArgTypeNames.at(ii));
-        }
-        if (unknownArgument)
-            continue; // We don't understand all the parameters
+        for (int ii = 0; ii < methodArgumentCount; ++ii) 
+            methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]);
 
         if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
             best = attempt;
@@ -1732,7 +1736,7 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativeP
         return CallPrecise(object, *best, engine, callArgs);
     } else {
         QString error = QLatin1String("Unable to determine callable overload.  Candidates are:");
-        const QDeclarativePropertyCache::Data *candidate = &data;
+        const QDeclarativePropertyData *candidate = &data;
         while (candidate) {
             error += QLatin1String("\n    ") + 
                      QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature());
@@ -1828,11 +1832,11 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
         }
     }
 
-    QDeclarativePropertyCache::Data method;
+    QDeclarativePropertyData method;
 
     if (QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(object)->declarativeData)) {
         if (ddata->propertyCache) {
-            QDeclarativePropertyCache::Data *d = ddata->propertyCache->method(index);
+            QDeclarativePropertyData *d = ddata->propertyCache->method(index);
             if (!d) 
                 return v8::Undefined();
             method = *d;
@@ -1840,7 +1844,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
     }
 
     if (method.coreIndex == -1) {
-        QMetaMethod mm = object->metaObject()->method(index);
         method.load(object->metaObject()->method(index));
 
         if (method.coreIndex == -1)
@@ -1864,7 +1867,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
     }
 
     CallArgs callArgs(argCount, &arguments);
-    if (method.relatedIndex == -1) {
+    if (!method.isOverload()) {
         return CallPrecise(object, method, resource->engine, callArgs);
     } else {
         return CallOverloaded(object, method, resource->engine, callArgs);
@@ -2054,3 +2057,6 @@ v8::Handle<v8::Value> MetaCallArgument::toValue(QV8Engine *engine)
         return v8::Undefined();
     }
 }
+
+QT_END_NAMESPACE
+