Home | History | Annotate | Download | only in qt
      1 /*
      2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Lesser General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Lesser General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Lesser General Public
     15  *  License along with this library; if not, write to the Free Software
     16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     17  *
     18  */
     19 
     20 #include "config.h"
     21 #include "qt_runtime.h"
     22 
     23 #include "BooleanObject.h"
     24 #include "DateInstance.h"
     25 #include "DateMath.h"
     26 #include "DatePrototype.h"
     27 #include "DumpRenderTreeSupportQt.h"
     28 #include "FunctionPrototype.h"
     29 #include "Interpreter.h"
     30 #include "JSArray.h"
     31 #include "JSByteArray.h"
     32 #include "JSDocument.h"
     33 #include "JSDOMBinding.h"
     34 #include "JSDOMWindow.h"
     35 #include <JSFunction.h>
     36 #include "JSGlobalObject.h"
     37 #include "JSHTMLElement.h"
     38 #include "JSLock.h"
     39 #include "JSObject.h"
     40 #include "ObjectPrototype.h"
     41 #include "PropertyNameArray.h"
     42 #include "RegExpConstructor.h"
     43 #include "RegExpObject.h"
     44 #include "qdatetime.h"
     45 #include "qdebug.h"
     46 #include "qmetaobject.h"
     47 #include "qmetatype.h"
     48 #include "qobject.h"
     49 #include "qstringlist.h"
     50 #include "qt_instance.h"
     51 #include "qt_pixmapruntime.h"
     52 #include "qvarlengtharray.h"
     53 #include "qwebelement.h"
     54 #include <limits.h>
     55 #include <runtime/Error.h>
     56 #include <runtime_array.h>
     57 #include <runtime_object.h>
     58 
     59 // QtScript has these
     60 Q_DECLARE_METATYPE(QObjectList);
     61 Q_DECLARE_METATYPE(QList<int>);
     62 Q_DECLARE_METATYPE(QVariant);
     63 
     64 using namespace WebCore;
     65 
     66 namespace JSC {
     67 namespace Bindings {
     68 
     69 // Debugging
     70 //#define QTWK_RUNTIME_CONVERSION_DEBUG
     71 //#define QTWK_RUNTIME_MATCH_DEBUG
     72 
     73 class QWKNoDebug
     74 {
     75 public:
     76     inline QWKNoDebug(){}
     77     inline ~QWKNoDebug(){}
     78 
     79     template<typename T>
     80     inline QWKNoDebug &operator<<(const T &) { return *this; }
     81 };
     82 
     83 #ifdef QTWK_RUNTIME_CONVERSION_DEBUG
     84 #define qConvDebug() qDebug()
     85 #else
     86 #define qConvDebug() QWKNoDebug()
     87 #endif
     88 
     89 #ifdef QTWK_RUNTIME_MATCH_DEBUG
     90 #define qMatchDebug() qDebug()
     91 #else
     92 #define qMatchDebug() QWKNoDebug()
     93 #endif
     94 
     95 typedef enum {
     96     Variant = 0,
     97     Number,
     98     Boolean,
     99     String,
    100     Date,
    101     RegExp,
    102     Array,
    103     QObj,
    104     Object,
    105     Null,
    106     RTArray,
    107     JSByteArray
    108 } JSRealType;
    109 
    110 #if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
    111 QDebug operator<<(QDebug dbg, const JSRealType &c)
    112 {
    113      const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
    114          "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
    115 
    116      dbg.nospace() << "JSType(" << ((int)c) << ", " <<  map[c] << ")";
    117 
    118      return dbg.space();
    119 }
    120 #endif
    121 
    122 // this is here as a proxy, so we'd have a class to friend in QWebElement,
    123 // as getting/setting a WebCore in QWebElement is private
    124 class QtWebElementRuntime {
    125 public:
    126     static QWebElement create(Element* element)
    127     {
    128         return QWebElement(element);
    129     }
    130 
    131     static Element* get(const QWebElement& element)
    132     {
    133         return element.m_element;
    134     }
    135 };
    136 
    137 // this is here as a proxy, so we'd have a class to friend in QDRTNode,
    138 // as getting/setting a WebCore in QDRTNode is private.
    139 // We only need to pass WebCore Nodes for layout tests.
    140 class QtDRTNodeRuntime {
    141 public:
    142     static QDRTNode create(Node* node)
    143     {
    144         return QDRTNode(node);
    145     }
    146 
    147     static Node* get(const QDRTNode& node)
    148     {
    149         return node.m_node;
    150     }
    151 };
    152 
    153 static JSRealType valueRealType(ExecState* exec, JSValue val)
    154 {
    155     if (val.isNumber())
    156         return Number;
    157     else if (val.isString())
    158         return String;
    159     else if (val.isBoolean())
    160         return Boolean;
    161     else if (val.isNull())
    162         return Null;
    163     else if (isJSByteArray(&exec->globalData(), val))
    164         return JSByteArray;
    165     else if (val.isObject()) {
    166         JSObject *object = val.toObject(exec);
    167         if (object->inherits(&RuntimeArray::s_info))  // RuntimeArray 'inherits' from Array, but not in C++
    168             return RTArray;
    169         else if (object->inherits(&JSArray::s_info))
    170             return Array;
    171         else if (object->inherits(&DateInstance::s_info))
    172             return Date;
    173         else if (object->inherits(&RegExpObject::s_info))
    174             return RegExp;
    175         else if (object->inherits(&RuntimeObject::s_info))
    176             return QObj;
    177         return Object;
    178     }
    179 
    180     return String; // I don't know.
    181 }
    182 
    183 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
    184 {
    185     --recursionLimit;
    186 
    187     if (!value || !recursionLimit)
    188         return QVariant();
    189 
    190     JSObject* object = 0;
    191     if (value.isObject()) {
    192         object = value.toObject(exec);
    193         if (visitedObjects->contains(object))
    194             return QVariant();
    195 
    196         visitedObjects->add(object);
    197     }
    198 
    199     // check magic pointer values before dereferencing value
    200     if (value == jsNaN()
    201         || (value == jsUndefined()
    202             && hint != QMetaType::QString
    203             && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
    204         if (distance)
    205             *distance = -1;
    206         return QVariant();
    207     }
    208 
    209     JSLock lock(SilenceAssertionsOnly);
    210     JSRealType type = valueRealType(exec, value);
    211     if (hint == QMetaType::Void) {
    212         switch(type) {
    213             case Number:
    214                 hint = QMetaType::Double;
    215                 break;
    216             case Boolean:
    217                 hint = QMetaType::Bool;
    218                 break;
    219             case String:
    220             default:
    221                 hint = QMetaType::QString;
    222                 break;
    223             case Date:
    224                 hint = QMetaType::QDateTime;
    225                 break;
    226             case RegExp:
    227                 hint = QMetaType::QRegExp;
    228                 break;
    229             case Object:
    230                 if (object->inherits(&NumberObject::s_info))
    231                     hint = QMetaType::Double;
    232                 else if (object->inherits(&BooleanObject::s_info))
    233                     hint = QMetaType::Bool;
    234                 else
    235                     hint = QMetaType::QVariantMap;
    236                 break;
    237             case QObj:
    238                 hint = QMetaType::QObjectStar;
    239                 break;
    240             case JSByteArray:
    241                 hint = QMetaType::QByteArray;
    242                 break;
    243             case Array:
    244             case RTArray:
    245                 hint = QMetaType::QVariantList;
    246                 break;
    247         }
    248     }
    249 
    250     qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
    251 
    252     if (value == jsNull()
    253         && hint != QMetaType::QObjectStar
    254         && hint != QMetaType::VoidStar
    255         && hint != QMetaType::QString
    256         && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
    257         if (distance)
    258             *distance = -1;
    259         return QVariant();
    260     }
    261 
    262     QVariant ret;
    263     int dist = -1;
    264     switch (hint) {
    265         case QMetaType::Bool:
    266             if (type == Object && object->inherits(&BooleanObject::s_info))
    267                 ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
    268             else
    269                 ret = QVariant(value.toBoolean(exec));
    270             if (type == Boolean)
    271                 dist = 0;
    272             else
    273                 dist = 10;
    274             break;
    275 
    276         case QMetaType::Int:
    277         case QMetaType::UInt:
    278         case QMetaType::Long:
    279         case QMetaType::ULong:
    280         case QMetaType::LongLong:
    281         case QMetaType::ULongLong:
    282         case QMetaType::Short:
    283         case QMetaType::UShort:
    284         case QMetaType::Float:
    285         case QMetaType::Double:
    286             ret = QVariant(value.toNumber(exec));
    287             ret.convert((QVariant::Type)hint);
    288             if (type == Number) {
    289                 switch (hint) {
    290                 case QMetaType::Double:
    291                     dist = 0;
    292                     break;
    293                 case QMetaType::Float:
    294                     dist = 1;
    295                     break;
    296                 case QMetaType::LongLong:
    297                 case QMetaType::ULongLong:
    298                     dist = 2;
    299                     break;
    300                 case QMetaType::Long:
    301                 case QMetaType::ULong:
    302                     dist = 3;
    303                     break;
    304                 case QMetaType::Int:
    305                 case QMetaType::UInt:
    306                     dist = 4;
    307                     break;
    308                 case QMetaType::Short:
    309                 case QMetaType::UShort:
    310                     dist = 5;
    311                     break;
    312                     break;
    313                 default:
    314                     dist = 10;
    315                     break;
    316                 }
    317             } else {
    318                 dist = 10;
    319             }
    320             break;
    321 
    322         case QMetaType::QChar:
    323             if (type == Number || type == Boolean) {
    324                 ret = QVariant(QChar((ushort)value.toNumber(exec)));
    325                 if (type == Boolean)
    326                     dist = 3;
    327                 else
    328                     dist = 6;
    329             } else {
    330                 UString str = value.toString(exec);
    331                 ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
    332                 if (type == String)
    333                     dist = 3;
    334                 else
    335                     dist = 10;
    336             }
    337             break;
    338 
    339         case QMetaType::QString: {
    340             if (value.isUndefinedOrNull()) {
    341                 if (distance)
    342                     *distance = 1;
    343                 return QString();
    344             } else {
    345                 UString ustring = value.toString(exec);
    346                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
    347                 if (type == String)
    348                     dist = 0;
    349                 else
    350                     dist = 10;
    351             }
    352             break;
    353         }
    354 
    355         case QMetaType::QVariantMap:
    356             if (type == Object || type == Array || type == RTArray) {
    357                 // Enumerate the contents of the object
    358                 PropertyNameArray properties(exec);
    359                 object->getPropertyNames(exec, properties);
    360                 PropertyNameArray::const_iterator it = properties.begin();
    361 
    362                 QVariantMap result;
    363                 int objdist = 0;
    364                 while(it != properties.end()) {
    365                     if (object->propertyIsEnumerable(exec, *it)) {
    366                         JSValue val = object->get(exec, *it);
    367                         QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
    368                         if (objdist >= 0) {
    369                             UString ustring = (*it).ustring();
    370                             QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    371                             result.insert(id, v);
    372                         }
    373                     }
    374                     ++it;
    375                 }
    376                 dist = 1;
    377                 ret = QVariant(result);
    378             }
    379             break;
    380 
    381         case QMetaType::QVariantList:
    382             if (type == RTArray) {
    383                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
    384 
    385                 QVariantList result;
    386                 int len = rtarray->getLength();
    387                 int objdist = 0;
    388                 qConvDebug() << "converting a " << len << " length Array";
    389                 for (int i = 0; i < len; ++i) {
    390                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
    391                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
    392                     if (objdist == -1) {
    393                         qConvDebug() << "Failed converting element at index " << i;
    394                         break; // Failed converting a list entry, so fail the array
    395                     }
    396                 }
    397                 if (objdist != -1) {
    398                     dist = 5;
    399                     ret = QVariant(result);
    400                 }
    401             } else if (type == Array) {
    402                 JSArray* array = static_cast<JSArray*>(object);
    403 
    404                 QVariantList result;
    405                 int len = array->length();
    406                 int objdist = 0;
    407                 qConvDebug() << "converting a " << len << " length Array";
    408                 for (int i = 0; i < len; ++i) {
    409                     JSValue val = array->get(exec, i);
    410                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
    411                     if (objdist == -1) {
    412                         qConvDebug() << "Failed converting element at index " << i;
    413                         break; // Failed converting a list entry, so fail the array
    414                     }
    415                 }
    416                 if (objdist != -1) {
    417                     dist = 5;
    418                     ret = QVariant(result);
    419                 }
    420             } else {
    421                 // Make a single length array
    422                 int objdist;
    423                 qConvDebug() << "making a single length variantlist";
    424                 QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
    425                 if (objdist != -1) {
    426                     QVariantList result;
    427                     result << var;
    428                     ret = QVariant(result);
    429                     dist = 10;
    430                 } else {
    431                     qConvDebug() << "failed making single length varlist";
    432                 }
    433             }
    434             break;
    435 
    436         case QMetaType::QStringList: {
    437             if (type == RTArray) {
    438                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
    439 
    440                 QStringList result;
    441                 int len = rtarray->getLength();
    442                 for (int i = 0; i < len; ++i) {
    443                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
    444                     UString ustring = val.toString(exec);
    445                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    446 
    447                     result.append(qstring);
    448                 }
    449                 dist = 5;
    450                 ret = QVariant(result);
    451             } else if (type == Array) {
    452                 JSArray* array = static_cast<JSArray*>(object);
    453 
    454                 QStringList result;
    455                 int len = array->length();
    456                 for (int i = 0; i < len; ++i) {
    457                     JSValue val = array->get(exec, i);
    458                     UString ustring = val.toString(exec);
    459                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    460 
    461                     result.append(qstring);
    462                 }
    463                 dist = 5;
    464                 ret = QVariant(result);
    465             } else {
    466                 // Make a single length array
    467                 UString ustring = value.toString(exec);
    468                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    469                 QStringList result;
    470                 result.append(qstring);
    471                 ret = QVariant(result);
    472                 dist = 10;
    473             }
    474             break;
    475         }
    476 
    477         case QMetaType::QByteArray: {
    478             if (type == JSByteArray) {
    479                 WTF::ByteArray* arr = asByteArray(value)->storage();
    480                 ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
    481                 dist = 0;
    482             } else {
    483                 UString ustring = value.toString(exec);
    484                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
    485                 if (type == String)
    486                     dist = 5;
    487                 else
    488                     dist = 10;
    489             }
    490             break;
    491         }
    492 
    493         case QMetaType::QDateTime:
    494         case QMetaType::QDate:
    495         case QMetaType::QTime:
    496             if (type == Date) {
    497                 DateInstance* date = static_cast<DateInstance*>(object);
    498                 GregorianDateTime gdt;
    499                 msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
    500                 if (hint == QMetaType::QDateTime) {
    501                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
    502                     dist = 0;
    503                 } else if (hint == QMetaType::QDate) {
    504                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
    505                     dist = 1;
    506                 } else {
    507                     ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
    508                     dist = 2;
    509                 }
    510             } else if (type == Number) {
    511                 double b = value.toNumber(exec);
    512                 GregorianDateTime gdt;
    513                 msToGregorianDateTime(exec, b, true, gdt);
    514                 if (hint == QMetaType::QDateTime) {
    515                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
    516                     dist = 6;
    517                 } else if (hint == QMetaType::QDate) {
    518                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
    519                     dist = 8;
    520                 } else {
    521                     ret = QTime(gdt.hour, gdt.minute, gdt.second);
    522                     dist = 10;
    523                 }
    524 #ifndef QT_NO_DATESTRING
    525             } else if (type == String) {
    526                 UString ustring = value.toString(exec);
    527                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    528 
    529                 if (hint == QMetaType::QDateTime) {
    530                     QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
    531                     if (!dt.isValid())
    532                         dt = QDateTime::fromString(qstring, Qt::TextDate);
    533                     if (!dt.isValid())
    534                         dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
    535                     if (!dt.isValid())
    536                         dt = QDateTime::fromString(qstring, Qt::LocaleDate);
    537                     if (dt.isValid()) {
    538                         ret = dt;
    539                         dist = 2;
    540                     }
    541                 } else if (hint == QMetaType::QDate) {
    542                     QDate dt = QDate::fromString(qstring, Qt::ISODate);
    543                     if (!dt.isValid())
    544                         dt = QDate::fromString(qstring, Qt::TextDate);
    545                     if (!dt.isValid())
    546                         dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
    547                     if (!dt.isValid())
    548                         dt = QDate::fromString(qstring, Qt::LocaleDate);
    549                     if (dt.isValid()) {
    550                         ret = dt;
    551                         dist = 3;
    552                     }
    553                 } else {
    554                     QTime dt = QTime::fromString(qstring, Qt::ISODate);
    555                     if (!dt.isValid())
    556                         dt = QTime::fromString(qstring, Qt::TextDate);
    557                     if (!dt.isValid())
    558                         dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
    559                     if (!dt.isValid())
    560                         dt = QTime::fromString(qstring, Qt::LocaleDate);
    561                     if (dt.isValid()) {
    562                         ret = dt;
    563                         dist = 3;
    564                     }
    565                 }
    566 #endif // QT_NO_DATESTRING
    567             }
    568             break;
    569 
    570         case QMetaType::QRegExp:
    571             if (type == RegExp) {
    572 /*
    573                 RegExpObject *re = static_cast<RegExpObject*>(object);
    574 */
    575                 // Attempt to convert.. a bit risky
    576                 UString ustring = value.toString(exec);
    577                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    578 
    579                 // this is of the form '/xxxxxx/i'
    580                 int firstSlash = qstring.indexOf(QLatin1Char('/'));
    581                 int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
    582                 if (firstSlash >=0 && lastSlash > firstSlash) {
    583                     QRegExp realRe;
    584 
    585                     realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
    586 
    587                     if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
    588                         realRe.setCaseSensitivity(Qt::CaseInsensitive);
    589 
    590                     ret = QVariant::fromValue(realRe);
    591                     dist = 0;
    592                 } else {
    593                     qConvDebug() << "couldn't parse a JS regexp";
    594                 }
    595             } else if (type == String) {
    596                 UString ustring = value.toString(exec);
    597                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
    598 
    599                 QRegExp re(qstring);
    600                 if (re.isValid()) {
    601                     ret = QVariant::fromValue(re);
    602                     dist = 10;
    603                 }
    604             }
    605             break;
    606 
    607         case QMetaType::QObjectStar:
    608             if (type == QObj) {
    609                 QtInstance* qtinst = QtInstance::getInstance(object);
    610                 if (qtinst) {
    611                     if (qtinst->getObject()) {
    612                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
    613                         ret = QVariant::fromValue(qtinst->getObject());
    614                         qConvDebug() << ret;
    615                         dist = 0;
    616                     } else {
    617                         qConvDebug() << "can't convert deleted qobject";
    618                     }
    619                 } else {
    620                     qConvDebug() << "wasn't a qtinstance";
    621                 }
    622             } else if (type == Null) {
    623                 QObject* nullobj = 0;
    624                 ret = QVariant::fromValue(nullobj);
    625                 dist = 0;
    626             } else {
    627                 qConvDebug() << "previous type was not an object:" << type;
    628             }
    629             break;
    630 
    631         case QMetaType::VoidStar:
    632             if (type == QObj) {
    633                 QtInstance* qtinst = QtInstance::getInstance(object);
    634                 if (qtinst) {
    635                     if (qtinst->getObject()) {
    636                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
    637                         ret = QVariant::fromValue((void *)qtinst->getObject());
    638                         qConvDebug() << ret;
    639                         dist = 0;
    640                     } else {
    641                         qConvDebug() << "can't convert deleted qobject";
    642                     }
    643                 } else {
    644                     qConvDebug() << "wasn't a qtinstance";
    645                 }
    646             } else if (type == Null) {
    647                 ret = QVariant::fromValue((void*)0);
    648                 dist = 0;
    649             } else if (type == Number) {
    650                 // I don't think that converting a double to a pointer is a wise
    651                 // move.  Except maybe 0.
    652                 qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
    653             } else {
    654                 qConvDebug() << "void* - unhandled type" << type;
    655             }
    656             break;
    657 
    658         default:
    659             // Non const type ids
    660             if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
    661             {
    662                 if (type == RTArray) {
    663                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
    664 
    665                     QObjectList result;
    666                     int len = rtarray->getLength();
    667                     for (int i = 0; i < len; ++i) {
    668                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
    669                         int itemdist = -1;
    670                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
    671                         if (itemdist >= 0)
    672                             result.append(item.value<QObject*>());
    673                         else
    674                             break;
    675                     }
    676                     // If we didn't fail conversion
    677                     if (result.count() == len) {
    678                         dist = 5;
    679                         ret = QVariant::fromValue(result);
    680                     }
    681                 } else if (type == Array) {
    682                     JSObject* object = value.toObject(exec);
    683                     JSArray* array = static_cast<JSArray *>(object);
    684                     QObjectList result;
    685                     int len = array->length();
    686                     for (int i = 0; i < len; ++i) {
    687                         JSValue val = array->get(exec, i);
    688                         int itemdist = -1;
    689                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
    690                         if (itemdist >= 0)
    691                             result.append(item.value<QObject*>());
    692                         else
    693                             break;
    694                     }
    695                     // If we didn't fail conversion
    696                     if (result.count() == len) {
    697                         dist = 5;
    698                         ret = QVariant::fromValue(result);
    699                     }
    700                 } else {
    701                     // Make a single length array
    702                     QObjectList result;
    703                     int itemdist = -1;
    704                     QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
    705                     if (itemdist >= 0) {
    706                         result.append(item.value<QObject*>());
    707                         dist = 10;
    708                         ret = QVariant::fromValue(result);
    709                     }
    710                 }
    711                 break;
    712             } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
    713                 if (type == RTArray) {
    714                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
    715 
    716                     QList<int> result;
    717                     int len = rtarray->getLength();
    718                     for (int i = 0; i < len; ++i) {
    719                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
    720                         int itemdist = -1;
    721                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
    722                         if (itemdist >= 0)
    723                             result.append(item.value<int>());
    724                         else
    725                             break;
    726                     }
    727                     // If we didn't fail conversion
    728                     if (result.count() == len) {
    729                         dist = 5;
    730                         ret = QVariant::fromValue(result);
    731                     }
    732                 } else if (type == Array) {
    733                     JSArray* array = static_cast<JSArray *>(object);
    734 
    735                     QList<int> result;
    736                     int len = array->length();
    737                     for (int i = 0; i < len; ++i) {
    738                         JSValue val = array->get(exec, i);
    739                         int itemdist = -1;
    740                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
    741                         if (itemdist >= 0)
    742                             result.append(item.value<int>());
    743                         else
    744                             break;
    745                     }
    746                     // If we didn't fail conversion
    747                     if (result.count() == len) {
    748                         dist = 5;
    749                         ret = QVariant::fromValue(result);
    750                     }
    751                 } else {
    752                     // Make a single length array
    753                     QList<int> result;
    754                     int itemdist = -1;
    755                     QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
    756                     if (itemdist >= 0) {
    757                         result.append(item.value<int>());
    758                         dist = 10;
    759                         ret = QVariant::fromValue(result);
    760                     }
    761                 }
    762                 break;
    763             } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
    764                 ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
    765             } else if (hint == (QMetaType::Type) qMetaTypeId<QWebElement>()) {
    766                 if (object && object->inherits(&JSHTMLElement::s_info))
    767                     ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSHTMLElement*>(object))->impl()));
    768                 else if (object && object->inherits(&JSDocument::s_info))
    769                     ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSDocument*>(object))->impl()->documentElement()));
    770                 else
    771                     ret = QVariant::fromValue<QWebElement>(QWebElement());
    772             } else if (hint == (QMetaType::Type) qMetaTypeId<QDRTNode>()) {
    773                 if (object && object->inherits(&JSNode::s_info))
    774                     ret = QVariant::fromValue<QDRTNode>(QtDRTNodeRuntime::create((static_cast<JSNode*>(object))->impl()));
    775             } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
    776                 if (value.isUndefinedOrNull()) {
    777                     if (distance)
    778                         *distance = 1;
    779                     return QVariant();
    780                 } else {
    781                     if (type == Object) {
    782                         // Since we haven't really visited this object yet, we remove it
    783                         visitedObjects->remove(object);
    784                     }
    785 
    786                     // And then recurse with the autodetect flag
    787                     ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
    788                     dist = 10;
    789                 }
    790                 break;
    791             }
    792 
    793             dist = 10;
    794             break;
    795     }
    796 
    797     if (!ret.isValid())
    798         dist = -1;
    799     if (distance)
    800         *distance = dist;
    801 
    802     return ret;
    803 }
    804 
    805 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
    806 {
    807     const int recursionLimit = 200;
    808     HashSet<JSObject*> visitedObjects;
    809     return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
    810 }
    811 
    812 JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
    813 {
    814     // Variants with QObject * can be isNull but not a null pointer
    815     // An empty QString variant is also null
    816     QMetaType::Type type = (QMetaType::Type) variant.userType();
    817 
    818     qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
    819     if (variant.isNull() &&
    820         type != QMetaType::QObjectStar &&
    821         type != QMetaType::VoidStar &&
    822         type != QMetaType::QWidgetStar &&
    823         type != QMetaType::QString) {
    824         return jsNull();
    825     }
    826 
    827     JSLock lock(SilenceAssertionsOnly);
    828 
    829     if (type == QMetaType::Bool)
    830         return jsBoolean(variant.toBool());
    831 
    832     if (type == QMetaType::Int ||
    833         type == QMetaType::UInt ||
    834         type == QMetaType::Long ||
    835         type == QMetaType::ULong ||
    836         type == QMetaType::LongLong ||
    837         type == QMetaType::ULongLong ||
    838         type == QMetaType::Short ||
    839         type == QMetaType::UShort ||
    840         type == QMetaType::Float ||
    841         type == QMetaType::Double)
    842         return jsNumber(variant.toDouble());
    843 
    844     if (type == QMetaType::QRegExp) {
    845         QRegExp re = variant.value<QRegExp>();
    846 
    847         if (re.isValid()) {
    848             UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
    849             RegExpFlags flags = (re.caseSensitivity() == Qt::CaseInsensitive) ? FlagIgnoreCase : NoFlags;
    850 
    851             RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, flags);
    852             if (regExp->isValid())
    853                 return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
    854             return jsNull();
    855         }
    856     }
    857 
    858     if (type == QMetaType::QDateTime ||
    859         type == QMetaType::QDate ||
    860         type == QMetaType::QTime) {
    861 
    862         QDate date = QDate::currentDate();
    863         QTime time(0,0,0); // midnight
    864 
    865         if (type == QMetaType::QDate)
    866             date = variant.value<QDate>();
    867         else if (type == QMetaType::QTime)
    868             time = variant.value<QTime>();
    869         else {
    870             QDateTime dt = variant.value<QDateTime>().toLocalTime();
    871             date = dt.date();
    872             time = dt.time();
    873         }
    874 
    875         // Dates specified this way are in local time (we convert DateTimes above)
    876         GregorianDateTime dt;
    877         dt.year = date.year() - 1900;
    878         dt.month = date.month() - 1;
    879         dt.monthDay = date.day();
    880         dt.hour = time.hour();
    881         dt.minute = time.minute();
    882         dt.second = time.second();
    883         dt.isDST = -1;
    884         double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
    885 
    886         return new (exec) DateInstance(exec, exec->lexicalGlobalObject()->dateStructure(), trunc(ms));
    887     }
    888 
    889     if (type == QMetaType::QByteArray) {
    890         QByteArray qtByteArray = variant.value<QByteArray>();
    891         WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
    892         memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
    893         return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(exec->globalData(), jsNull()), wtfByteArray.get());
    894     }
    895 
    896     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
    897         QObject* obj = variant.value<QObject*>();
    898         if (!obj)
    899             return jsNull();
    900         return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
    901     }
    902 
    903     if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
    904         return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
    905 
    906     if (type == qMetaTypeId<QWebElement>()) {
    907         if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
    908             return jsUndefined();
    909 
    910         Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
    911         if (!document)
    912             return jsUndefined();
    913 
    914         return toJS(exec, toJSDOMGlobalObject(document, exec), QtWebElementRuntime::get(variant.value<QWebElement>()));
    915     }
    916 
    917     if (type == qMetaTypeId<QDRTNode>()) {
    918         if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
    919             return jsUndefined();
    920 
    921         Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
    922         if (!document)
    923             return jsUndefined();
    924 
    925         return toJS(exec, toJSDOMGlobalObject(document, exec), QtDRTNodeRuntime::get(variant.value<QDRTNode>()));
    926     }
    927 
    928     if (type == QMetaType::QVariantMap) {
    929         // create a new object, and stuff properties into it
    930         JSObject* ret = constructEmptyObject(exec);
    931         QVariantMap map = variant.value<QVariantMap>();
    932         QVariantMap::const_iterator i = map.constBegin();
    933         while (i != map.constEnd()) {
    934             QString s = i.key();
    935             JSValue val = convertQVariantToValue(exec, root.get(), i.value());
    936             if (val) {
    937                 PutPropertySlot slot;
    938                 ret->put(exec, Identifier(exec, reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
    939                 // ### error case?
    940             }
    941             ++i;
    942         }
    943 
    944         return ret;
    945     }
    946 
    947     // List types
    948     if (type == QMetaType::QVariantList) {
    949         QVariantList vl = variant.toList();
    950         qConvDebug() << "got a " << vl.count() << " length list:" << vl;
    951         return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
    952     } else if (type == QMetaType::QStringList) {
    953         QStringList sl = variant.value<QStringList>();
    954         return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
    955     } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
    956         QObjectList ol= variant.value<QObjectList>();
    957         return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
    958     } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
    959         QList<int> il= variant.value<QList<int> >();
    960         return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
    961     }
    962 
    963     if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
    964         QVariant real = variant.value<QVariant>();
    965         qConvDebug() << "real variant is:" << real;
    966         return convertQVariantToValue(exec, root, real);
    967     }
    968 
    969     qConvDebug() << "fallback path for" << variant << variant.userType();
    970 
    971     QString string = variant.toString();
    972     UString ustring((UChar*)string.utf16(), string.length());
    973     return jsString(exec, ustring);
    974 }
    975 
    976 // ===============
    977 
    978 // Qt-like macros
    979 #define QW_D(Class) Class##Data* d = d_func()
    980 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
    981 
    982 const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0 };
    983 
    984 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
    985     : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject(), deprecatedGetDOMStructure<QtRuntimeMethod>(exec), ident)
    986     , d_ptr(dd)
    987 {
    988     QW_D(QtRuntimeMethod);
    989     d->m_instance = inst;
    990 }
    991 
    992 QtRuntimeMethod::~QtRuntimeMethod()
    993 {
    994     QW_D(QtRuntimeMethod);
    995     d->m_instance->removeCachedMethod(this);
    996     delete d_ptr;
    997 }
    998 
    999 // ===============
   1000 
   1001 QtRuntimeMethodData::~QtRuntimeMethodData()
   1002 {
   1003 }
   1004 
   1005 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
   1006 {
   1007 
   1008 }
   1009 
   1010 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
   1011 {
   1012 
   1013 }
   1014 
   1015 // ===============
   1016 
   1017 // Type conversion metadata (from QtScript originally)
   1018 class QtMethodMatchType
   1019 {
   1020 public:
   1021     enum Kind {
   1022         Invalid,
   1023         Variant,
   1024         MetaType,
   1025         Unresolved,
   1026         MetaEnum
   1027     };
   1028 
   1029 
   1030     QtMethodMatchType()
   1031         : m_kind(Invalid) { }
   1032 
   1033     Kind kind() const
   1034     { return m_kind; }
   1035 
   1036     QMetaType::Type typeId() const;
   1037 
   1038     bool isValid() const
   1039     { return (m_kind != Invalid); }
   1040 
   1041     bool isVariant() const
   1042     { return (m_kind == Variant); }
   1043 
   1044     bool isMetaType() const
   1045     { return (m_kind == MetaType); }
   1046 
   1047     bool isUnresolved() const
   1048     { return (m_kind == Unresolved); }
   1049 
   1050     bool isMetaEnum() const
   1051     { return (m_kind == MetaEnum); }
   1052 
   1053     QByteArray name() const;
   1054 
   1055     int enumeratorIndex() const
   1056     { Q_ASSERT(isMetaEnum()); return m_typeId; }
   1057 
   1058     static QtMethodMatchType variant()
   1059     { return QtMethodMatchType(Variant); }
   1060 
   1061     static QtMethodMatchType metaType(int typeId, const QByteArray &name)
   1062     { return QtMethodMatchType(MetaType, typeId, name); }
   1063 
   1064     static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
   1065     { return QtMethodMatchType(MetaEnum, enumIndex, name); }
   1066 
   1067     static QtMethodMatchType unresolved(const QByteArray &name)
   1068     { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
   1069 
   1070 private:
   1071     QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
   1072         : m_kind(kind), m_typeId(typeId), m_name(name) { }
   1073 
   1074     Kind m_kind;
   1075     int m_typeId;
   1076     QByteArray m_name;
   1077 };
   1078 
   1079 QMetaType::Type QtMethodMatchType::typeId() const
   1080 {
   1081     if (isVariant())
   1082         return (QMetaType::Type) QMetaType::type("QVariant");
   1083     return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
   1084 }
   1085 
   1086 QByteArray QtMethodMatchType::name() const
   1087 {
   1088     if (!m_name.isEmpty())
   1089         return m_name;
   1090     else if (m_kind == Variant)
   1091         return "QVariant";
   1092     return QByteArray();
   1093 }
   1094 
   1095 struct QtMethodMatchData
   1096 {
   1097     int matchDistance;
   1098     int index;
   1099     QVector<QtMethodMatchType> types;
   1100     QVarLengthArray<QVariant, 10> args;
   1101 
   1102     QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
   1103                                 const QVarLengthArray<QVariant, 10> &as)
   1104         : matchDistance(dist), index(idx), types(typs), args(as) { }
   1105     QtMethodMatchData()
   1106         : index(-1) { }
   1107 
   1108     bool isValid() const
   1109     { return (index != -1); }
   1110 
   1111     int firstUnresolvedIndex() const
   1112     {
   1113         for (int i=0; i < types.count(); i++) {
   1114             if (types.at(i).isUnresolved())
   1115                 return i;
   1116         }
   1117         return -1;
   1118     }
   1119 };
   1120 
   1121 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
   1122 {
   1123     QByteArray scope;
   1124     QByteArray name;
   1125     int scopeIdx = str.indexOf("::");
   1126     if (scopeIdx != -1) {
   1127         scope = str.left(scopeIdx);
   1128         name = str.mid(scopeIdx + 2);
   1129     } else {
   1130         name = str;
   1131     }
   1132     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
   1133         QMetaEnum m = meta->enumerator(i);
   1134         if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
   1135             return i;
   1136     }
   1137     return -1;
   1138 }
   1139 
   1140 // Helper function for resolving methods
   1141 // Largely based on code in QtScript for compatibility reasons
   1142 static int findMethodIndex(ExecState* exec,
   1143                            const QMetaObject* meta,
   1144                            const QByteArray& signature,
   1145                            bool allowPrivate,
   1146                            QVarLengthArray<QVariant, 10> &vars,
   1147                            void** vvars,
   1148                            JSObject **pError)
   1149 {
   1150     QList<int> matchingIndices;
   1151 
   1152     bool overloads = !signature.contains('(');
   1153 
   1154     int count = meta->methodCount();
   1155     for (int i = count - 1; i >= 0; --i) {
   1156         const QMetaMethod m = meta->method(i);
   1157 
   1158         // Don't choose private methods
   1159         if (m.access() == QMetaMethod::Private && !allowPrivate)
   1160             continue;
   1161 
   1162         // try and find all matching named methods
   1163         if (m.signature() == signature)
   1164             matchingIndices.append(i);
   1165         else if (overloads) {
   1166             QByteArray rawsignature = m.signature();
   1167             rawsignature.truncate(rawsignature.indexOf('('));
   1168             if (rawsignature == signature)
   1169                 matchingIndices.append(i);
   1170         }
   1171     }
   1172 
   1173     int chosenIndex = -1;
   1174     *pError = 0;
   1175     QVector<QtMethodMatchType> chosenTypes;
   1176 
   1177     QVarLengthArray<QVariant, 10> args;
   1178     QVector<QtMethodMatchData> candidates;
   1179     QVector<QtMethodMatchData> unresolved;
   1180     QVector<int> tooFewArgs;
   1181     QVector<int> conversionFailed;
   1182 
   1183     foreach(int index, matchingIndices) {
   1184         QMetaMethod method = meta->method(index);
   1185 
   1186         QVector<QtMethodMatchType> types;
   1187         bool unresolvedTypes = false;
   1188 
   1189         // resolve return type
   1190         QByteArray returnTypeName = method.typeName();
   1191         int rtype = QMetaType::type(returnTypeName);
   1192         if ((rtype == 0) && !returnTypeName.isEmpty()) {
   1193             if (returnTypeName == "QVariant") {
   1194                 types.append(QtMethodMatchType::variant());
   1195             } else if (returnTypeName.endsWith('*')) {
   1196                 types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
   1197             } else {
   1198                 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
   1199                 if (enumIndex != -1)
   1200                     types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
   1201                 else {
   1202                     unresolvedTypes = true;
   1203                     types.append(QtMethodMatchType::unresolved(returnTypeName));
   1204                 }
   1205             }
   1206         } else {
   1207             if (returnTypeName == "QVariant")
   1208                 types.append(QtMethodMatchType::variant());
   1209             else
   1210                 types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
   1211         }
   1212 
   1213         // resolve argument types
   1214         QList<QByteArray> parameterTypeNames = method.parameterTypes();
   1215         for (int i = 0; i < parameterTypeNames.count(); ++i) {
   1216             QByteArray argTypeName = parameterTypeNames.at(i);
   1217             int atype = QMetaType::type(argTypeName);
   1218             if (atype == 0) {
   1219                 if (argTypeName == "QVariant") {
   1220                     types.append(QtMethodMatchType::variant());
   1221                 } else {
   1222                     int enumIndex = indexOfMetaEnum(meta, argTypeName);
   1223                     if (enumIndex != -1)
   1224                         types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
   1225                     else {
   1226                         unresolvedTypes = true;
   1227                         types.append(QtMethodMatchType::unresolved(argTypeName));
   1228                     }
   1229                 }
   1230             } else {
   1231                 if (argTypeName == "QVariant")
   1232                     types.append(QtMethodMatchType::variant());
   1233                 else
   1234                     types.append(QtMethodMatchType::metaType(atype, argTypeName));
   1235             }
   1236         }
   1237 
   1238         // If the native method requires more arguments than what was passed from JavaScript
   1239         if (exec->argumentCount() + 1 < static_cast<unsigned>(types.count())) {
   1240             qMatchDebug() << "Match:too few args for" << method.signature();
   1241             tooFewArgs.append(index);
   1242             continue;
   1243         }
   1244 
   1245         if (unresolvedTypes) {
   1246             qMatchDebug() << "Match:unresolved arg types for" << method.signature();
   1247             // remember it so we can give an error message later, if necessary
   1248             unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
   1249                                                    types, QVarLengthArray<QVariant, 10>()));
   1250             continue;
   1251         }
   1252 
   1253         // Now convert arguments
   1254         if (args.count() != types.count())
   1255             args.resize(types.count());
   1256 
   1257         QtMethodMatchType retType = types[0];
   1258         args[0] = QVariant(retType.typeId(), (void *)0); // the return value
   1259 
   1260         bool converted = true;
   1261         int matchDistance = 0;
   1262         for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
   1263             JSValue arg = i < exec->argumentCount() ? exec->argument(i) : jsUndefined();
   1264 
   1265             int argdistance = -1;
   1266             QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
   1267             if (argdistance >= 0) {
   1268                 matchDistance += argdistance;
   1269                 args[i+1] = v;
   1270             } else {
   1271                 qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
   1272                 converted = false;
   1273             }
   1274         }
   1275 
   1276         qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
   1277 
   1278         if (converted) {
   1279             if ((exec->argumentCount() + 1 == static_cast<unsigned>(types.count()))
   1280                 && (matchDistance == 0)) {
   1281                 // perfect match, use this one
   1282                 chosenIndex = index;
   1283                 break;
   1284             } else {
   1285                 QtMethodMatchData currentMatch(matchDistance, index, types, args);
   1286                 if (candidates.isEmpty()) {
   1287                     candidates.append(currentMatch);
   1288                 } else {
   1289                     QtMethodMatchData bestMatchSoFar = candidates.at(0);
   1290                     if ((args.count() > bestMatchSoFar.args.count())
   1291                         || ((args.count() == bestMatchSoFar.args.count())
   1292                             && (matchDistance <= bestMatchSoFar.matchDistance))) {
   1293                         candidates.prepend(currentMatch);
   1294                     } else {
   1295                         candidates.append(currentMatch);
   1296                     }
   1297                 }
   1298             }
   1299         } else {
   1300             conversionFailed.append(index);
   1301         }
   1302 
   1303         if (!overloads)
   1304             break;
   1305     }
   1306 
   1307     if (chosenIndex == -1 && candidates.count() == 0) {
   1308         // No valid functions at all - format an error message
   1309         if (!conversionFailed.isEmpty()) {
   1310             QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
   1311                               .arg(QLatin1String(signature));
   1312             for (int i = 0; i < conversionFailed.size(); ++i) {
   1313                 if (i > 0)
   1314                     message += QLatin1String("\n");
   1315                 QMetaMethod mtd = meta->method(conversionFailed.at(i));
   1316                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
   1317             }
   1318             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
   1319         } else if (!unresolved.isEmpty()) {
   1320             QtMethodMatchData argsInstance = unresolved.first();
   1321             int unresolvedIndex = argsInstance.firstUnresolvedIndex();
   1322             Q_ASSERT(unresolvedIndex != -1);
   1323             QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
   1324             QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
   1325                 .arg(QString::fromLatin1(signature))
   1326                 .arg(QLatin1String(unresolvedType.name()));
   1327             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
   1328         } else {
   1329             QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
   1330                               .arg(QLatin1String(signature));
   1331             for (int i = 0; i < tooFewArgs.size(); ++i) {
   1332                 if (i > 0)
   1333                     message += QLatin1String("\n");
   1334                 QMetaMethod mtd = meta->method(tooFewArgs.at(i));
   1335                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
   1336             }
   1337             *pError = throwError(exec, createSyntaxError(exec, message.toLatin1().constData()));
   1338         }
   1339     }
   1340 
   1341     if (chosenIndex == -1 && candidates.count() > 0) {
   1342         QtMethodMatchData bestMatch = candidates.at(0);
   1343         if ((candidates.size() > 1)
   1344             && (bestMatch.args.count() == candidates.at(1).args.count())
   1345             && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
   1346             // ambiguous call
   1347             QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
   1348                                 .arg(QLatin1String(signature));
   1349             for (int i = 0; i < candidates.size(); ++i) {
   1350                 // Only candidate for overload if argument count and match distance is same as best match
   1351                 if (candidates.at(i).args.count() == bestMatch.args.count()
   1352                     || candidates.at(i).matchDistance == bestMatch.matchDistance) {
   1353                     if (i > 0)
   1354                         message += QLatin1String("\n");
   1355                     QMetaMethod mtd = meta->method(candidates.at(i).index);
   1356                     message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
   1357                 }
   1358             }
   1359             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
   1360         } else {
   1361             chosenIndex = bestMatch.index;
   1362             args = bestMatch.args;
   1363         }
   1364     }
   1365 
   1366     if (chosenIndex != -1) {
   1367         /* Copy the stuff over */
   1368         int i;
   1369         vars.resize(args.count());
   1370         for (i=0; i < args.count(); i++) {
   1371             vars[i] = args[i];
   1372             vvars[i] = vars[i].data();
   1373         }
   1374     }
   1375 
   1376     return chosenIndex;
   1377 }
   1378 
   1379 // Signals are not fuzzy matched as much as methods
   1380 static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
   1381 {
   1382     int index = initialIndex;
   1383     QMetaMethod method = meta->method(index);
   1384     bool overloads = !signature.contains('(');
   1385     if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
   1386         // find the most general method
   1387         do {
   1388             method = meta->method(--index);
   1389         } while (method.attributes() & QMetaMethod::Cloned);
   1390     }
   1391     return index;
   1392 }
   1393 
   1394 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
   1395     : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
   1396 {
   1397     QW_D(QtRuntimeMetaMethod);
   1398     d->m_signature = signature;
   1399     d->m_index = index;
   1400     d->m_allowPrivate = allowPrivate;
   1401 }
   1402 
   1403 void QtRuntimeMetaMethod::markChildren(MarkStack& markStack)
   1404 {
   1405     QtRuntimeMethod::markChildren(markStack);
   1406     QW_D(QtRuntimeMetaMethod);
   1407     if (d->m_connect)
   1408         markStack.append(&d->m_connect);
   1409     if (d->m_disconnect)
   1410         markStack.append(&d->m_disconnect);
   1411 }
   1412 
   1413 EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
   1414 {
   1415     QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
   1416 
   1417     // We're limited to 10 args
   1418     if (exec->argumentCount() > 10)
   1419         return JSValue::encode(jsUndefined());
   1420 
   1421     // We have to pick a method that matches..
   1422     JSLock lock(SilenceAssertionsOnly);
   1423 
   1424     QObject *obj = d->m_instance->getObject();
   1425     if (obj) {
   1426         QVarLengthArray<QVariant, 10> vargs;
   1427         void *qargs[11];
   1428 
   1429         int methodIndex;
   1430         JSObject* errorObj = 0;
   1431         if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, vargs, (void **)qargs, &errorObj)) != -1) {
   1432             if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
   1433                 return JSValue::encode(jsUndefined());
   1434 
   1435             if (vargs[0].isValid())
   1436                 return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
   1437         }
   1438 
   1439         if (errorObj)
   1440             return JSValue::encode(errorObj);
   1441     } else {
   1442         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
   1443     }
   1444 
   1445     // void functions return undefined
   1446     return JSValue::encode(jsUndefined());
   1447 }
   1448 
   1449 CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
   1450 {
   1451     callData.native.function = call;
   1452     return CallTypeHost;
   1453 }
   1454 
   1455 bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
   1456 {
   1457     if (propertyName == "connect") {
   1458         slot.setCustom(this, connectGetter);
   1459         return true;
   1460     } else if (propertyName == "disconnect") {
   1461         slot.setCustom(this, disconnectGetter);
   1462         return true;
   1463     } else if (propertyName == exec->propertyNames().length) {
   1464         slot.setCustom(this, lengthGetter);
   1465         return true;
   1466     }
   1467 
   1468     return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
   1469 }
   1470 
   1471 bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
   1472 {
   1473     if (propertyName == "connect") {
   1474         PropertySlot slot;
   1475         slot.setCustom(this, connectGetter);
   1476         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
   1477         return true;
   1478     }
   1479 
   1480     if (propertyName == "disconnect") {
   1481         PropertySlot slot;
   1482         slot.setCustom(this, disconnectGetter);
   1483         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
   1484         return true;
   1485     }
   1486 
   1487     if (propertyName == exec->propertyNames().length) {
   1488         PropertySlot slot;
   1489         slot.setCustom(this, lengthGetter);
   1490         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
   1491         return true;
   1492     }
   1493 
   1494     return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
   1495 }
   1496 
   1497 void QtRuntimeMetaMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
   1498 {
   1499     if (mode == IncludeDontEnumProperties) {
   1500         propertyNames.add(Identifier(exec, "connect"));
   1501         propertyNames.add(Identifier(exec, "disconnect"));
   1502         propertyNames.add(exec->propertyNames().length);
   1503     }
   1504 
   1505     QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
   1506 }
   1507 
   1508 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
   1509 {
   1510     // QtScript always returns 0
   1511     return jsNumber(0);
   1512 }
   1513 
   1514 JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
   1515 {
   1516     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
   1517     QW_DS(QtRuntimeMetaMethod, thisObj);
   1518 
   1519     if (!d->m_connect)
   1520         d->m_connect.set(exec->globalData(), thisObj, new (exec) QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature));
   1521     return d->m_connect.get();
   1522 }
   1523 
   1524 JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
   1525 {
   1526     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
   1527     QW_DS(QtRuntimeMetaMethod, thisObj);
   1528 
   1529     if (!d->m_disconnect)
   1530         d->m_disconnect.set(exec->globalData(), thisObj, new (exec) QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature));
   1531     return d->m_disconnect.get();
   1532 }
   1533 
   1534 // ===============
   1535 
   1536 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
   1537 
   1538 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
   1539     : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
   1540 {
   1541     QW_D(QtRuntimeConnectionMethod);
   1542 
   1543     d->m_signature = signature;
   1544     d->m_index = index;
   1545     d->m_isConnect = isConnect;
   1546 }
   1547 
   1548 EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
   1549 {
   1550     QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
   1551 
   1552     JSLock lock(SilenceAssertionsOnly);
   1553 
   1554     QObject* sender = d->m_instance->getObject();
   1555 
   1556     if (sender) {
   1557 
   1558         JSObject* thisObject = exec->lexicalGlobalObject();
   1559         JSObject* funcObject = 0;
   1560 
   1561         // QtScript checks signalness first, arguments second
   1562         int signalIndex = -1;
   1563 
   1564         // Make sure the initial index is a signal
   1565         QMetaMethod m = sender->metaObject()->method(d->m_index);
   1566         if (m.methodType() == QMetaMethod::Signal)
   1567             signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
   1568 
   1569         if (signalIndex != -1) {
   1570             if (exec->argumentCount() == 1) {
   1571                 funcObject = exec->argument(0).toObject(exec);
   1572                 CallData callData;
   1573                 if (funcObject->getCallData(callData) == CallTypeNone) {
   1574                     if (d->m_isConnect)
   1575                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
   1576                     else
   1577                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
   1578                 }
   1579             } else if (exec->argumentCount() >= 2) {
   1580                 if (exec->argument(0).isObject()) {
   1581                     thisObject = exec->argument(0).toObject(exec);
   1582 
   1583                     // Get the actual function to call
   1584                     JSObject *asObj = exec->argument(1).toObject(exec);
   1585                     CallData callData;
   1586                     if (asObj->getCallData(callData) != CallTypeNone) {
   1587                         // Function version
   1588                         funcObject = asObj;
   1589                     } else {
   1590                         // Convert it to a string
   1591                         UString funcName = exec->argument(1).toString(exec);
   1592                         Identifier funcIdent(exec, funcName);
   1593 
   1594                         // ### DropAllLocks
   1595                         // This is resolved at this point in QtScript
   1596                         JSValue val = thisObject->get(exec, funcIdent);
   1597                         JSObject* asFuncObj = val.toObject(exec);
   1598 
   1599                         if (asFuncObj->getCallData(callData) != CallTypeNone) {
   1600                             funcObject = asFuncObj;
   1601                         } else {
   1602                             if (d->m_isConnect)
   1603                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
   1604                             else
   1605                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
   1606                         }
   1607                     }
   1608                 } else {
   1609                     if (d->m_isConnect)
   1610                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
   1611                     else
   1612                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
   1613                 }
   1614             } else {
   1615                 if (d->m_isConnect)
   1616                     return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
   1617                 else
   1618                     return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
   1619             }
   1620 
   1621             if (d->m_isConnect) {
   1622                 // to connect, we need:
   1623                 //  target object [from ctor]
   1624                 //  target signal index etc. [from ctor]
   1625                 //  receiver function [from arguments]
   1626                 //  receiver this object [from arguments]
   1627 
   1628                 QtConnectionObject* conn = new QtConnectionObject(exec->globalData(), d->m_instance, signalIndex, thisObject, funcObject);
   1629                 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
   1630                 if (!ok) {
   1631                     delete conn;
   1632                     QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
   1633                             .arg(QLatin1String(sender->metaObject()->className()))
   1634                             .arg(QLatin1String(d->m_signature));
   1635                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
   1636                 }
   1637                 else {
   1638                     // Store connection
   1639                     connections.insert(sender, conn);
   1640                 }
   1641             } else {
   1642                 // Now to find our previous connection object. Hmm.
   1643                 QList<QtConnectionObject*> conns = connections.values(sender);
   1644                 bool ret = false;
   1645 
   1646                 foreach(QtConnectionObject* conn, conns) {
   1647                     // Is this the right connection?
   1648                     if (conn->match(sender, signalIndex, thisObject, funcObject)) {
   1649                         // Yep, disconnect it
   1650                         QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
   1651                         delete conn; // this will also remove it from the map
   1652                         ret = true;
   1653                         break;
   1654                     }
   1655                 }
   1656 
   1657                 if (!ret) {
   1658                     QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
   1659                             .arg(QLatin1String(sender->metaObject()->className()))
   1660                             .arg(QLatin1String(d->m_signature));
   1661                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
   1662                 }
   1663             }
   1664         } else {
   1665             QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
   1666                     .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
   1667                     .arg(QLatin1String(sender->metaObject()->className()))
   1668                     .arg(QLatin1String(d->m_signature));
   1669             return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
   1670         }
   1671     } else {
   1672         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
   1673     }
   1674 
   1675     return JSValue::encode(jsUndefined());
   1676 }
   1677 
   1678 CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
   1679 {
   1680     callData.native.function = call;
   1681     return CallTypeHost;
   1682 }
   1683 
   1684 bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
   1685 {
   1686     if (propertyName == exec->propertyNames().length) {
   1687         slot.setCustom(this, lengthGetter);
   1688         return true;
   1689     }
   1690 
   1691     return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
   1692 }
   1693 
   1694 bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
   1695 {
   1696     if (propertyName == exec->propertyNames().length) {
   1697         PropertySlot slot;
   1698         slot.setCustom(this, lengthGetter);
   1699         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
   1700         return true;
   1701     }
   1702 
   1703     return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
   1704 }
   1705 
   1706 void QtRuntimeConnectionMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
   1707 {
   1708     if (mode == IncludeDontEnumProperties)
   1709         propertyNames.add(exec->propertyNames().length);
   1710 
   1711     QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
   1712 }
   1713 
   1714 JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
   1715 {
   1716     // we have one formal argument, and one optional
   1717     return jsNumber(1);
   1718 }
   1719 
   1720 // ===============
   1721 
   1722 QtConnectionObject::QtConnectionObject(JSGlobalData& globalData, PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
   1723     : m_instance(instance)
   1724     , m_signalIndex(signalIndex)
   1725     , m_originalObject(m_instance->getObject())
   1726     , m_thisObject(globalData, thisObject)
   1727     , m_funcObject(globalData, funcObject)
   1728 {
   1729     setParent(m_originalObject);
   1730     ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
   1731 }
   1732 
   1733 QtConnectionObject::~QtConnectionObject()
   1734 {
   1735     // Remove us from the map of active connections
   1736     QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
   1737 }
   1738 
   1739 static const uint qt_meta_data_QtConnectionObject[] = {
   1740 
   1741  // content:
   1742        1,       // revision
   1743        0,       // classname
   1744        0,    0, // classinfo
   1745        1,   10, // methods
   1746        0,    0, // properties
   1747        0,    0, // enums/sets
   1748 
   1749  // slots: signature, parameters, type, tag, flags
   1750       28,   27,   27,   27, 0x0a,
   1751 
   1752        0        // eod
   1753 };
   1754 
   1755 static const char qt_meta_stringdata_QtConnectionObject[] = {
   1756     "JSC::Bindings::QtConnectionObject\0\0execute()\0"
   1757 };
   1758 
   1759 const QMetaObject QtConnectionObject::staticMetaObject = {
   1760     { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
   1761       qt_meta_data_QtConnectionObject, 0 }
   1762 };
   1763 
   1764 const QMetaObject *QtConnectionObject::metaObject() const
   1765 {
   1766     return &staticMetaObject;
   1767 }
   1768 
   1769 void *QtConnectionObject::qt_metacast(const char *_clname)
   1770 {
   1771     if (!_clname) return 0;
   1772     if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
   1773         return static_cast<void*>(const_cast<QtConnectionObject*>(this));
   1774     return QObject::qt_metacast(_clname);
   1775 }
   1776 
   1777 int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
   1778 {
   1779     _id = QObject::qt_metacall(_c, _id, _a);
   1780     if (_id < 0)
   1781         return _id;
   1782     if (_c == QMetaObject::InvokeMetaMethod) {
   1783         switch (_id) {
   1784         case 0: execute(_a); break;
   1785         }
   1786         _id -= 1;
   1787     }
   1788     return _id;
   1789 }
   1790 
   1791 void QtConnectionObject::execute(void **argv)
   1792 {
   1793     QObject* obj = m_instance->getObject();
   1794     if (obj) {
   1795         const QMetaObject* meta = obj->metaObject();
   1796         const QMetaMethod method = meta->method(m_signalIndex);
   1797 
   1798         QList<QByteArray> parameterTypes = method.parameterTypes();
   1799 
   1800         int argc = parameterTypes.count();
   1801 
   1802         JSLock lock(SilenceAssertionsOnly);
   1803 
   1804         // ### Should the Interpreter/ExecState come from somewhere else?
   1805         RefPtr<RootObject> ro = m_instance->rootObject();
   1806         if (ro) {
   1807             JSGlobalObject* globalobj = ro->globalObject();
   1808             if (globalobj) {
   1809                 ExecState* exec = globalobj->globalExec();
   1810                 if (exec) {
   1811                     // Build the argument list (up to the formal argument length of the slot)
   1812                     MarkedArgumentBuffer l;
   1813                     // ### DropAllLocks?
   1814                     int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
   1815                     int argTotal = qMax(funcArgC, argc);
   1816                     for(int i=0; i < argTotal; i++) {
   1817                         if (i < argc) {
   1818                             int argType = QMetaType::type(parameterTypes.at(i));
   1819                             l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
   1820                         } else {
   1821                             l.append(jsUndefined());
   1822                         }
   1823                     }
   1824                     // Stuff in the __qt_sender property, if we can
   1825                     ScopeChainNode* oldsc = 0;
   1826                     JSFunction* fimp = 0;
   1827                     if (m_funcObject->inherits(&JSFunction::s_info)) {
   1828                         fimp = static_cast<JSFunction*>(m_funcObject.get());
   1829 
   1830                         JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
   1831                         JSObject* wrapper = constructEmptyObject(exec, createEmptyObjectStructure(exec->globalData(), jsNull()));
   1832                         PutPropertySlot slot;
   1833                         wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
   1834                         oldsc = fimp->scope();
   1835                         fimp->setScope(exec->globalData(), oldsc->push(wrapper));
   1836                     }
   1837 
   1838                     CallData callData;
   1839                     CallType callType = m_funcObject->getCallData(callData);
   1840                     call(exec, m_funcObject.get(), callType, callData, m_thisObject.get(), l);
   1841 
   1842                     if (fimp)
   1843                         fimp->setScope(exec->globalData(), oldsc);
   1844                 }
   1845             }
   1846         }
   1847     } else {
   1848         // A strange place to be - a deleted object emitted a signal here.
   1849         qWarning() << "sender deleted, cannot deliver signal";
   1850     }
   1851 }
   1852 
   1853 bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
   1854 {
   1855     if (m_originalObject == sender && m_signalIndex == signalIndex
   1856         && thisObject == (JSObject*)m_thisObject.get() && funcObject == (JSObject*)m_funcObject.get())
   1857         return true;
   1858     return false;
   1859 }
   1860 
   1861 // ===============
   1862 
   1863 template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
   1864     : Array(rootObject)
   1865     , m_list(list)
   1866     , m_type(type)
   1867 {
   1868     m_length = m_list.count();
   1869 }
   1870 
   1871 template <typename T> QtArray<T>::~QtArray ()
   1872 {
   1873 }
   1874 
   1875 template <typename T> RootObject* QtArray<T>::rootObject() const
   1876 {
   1877     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
   1878 }
   1879 
   1880 template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
   1881 {
   1882     // QtScript sets the value, but doesn't forward it to the original source
   1883     // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
   1884     // copy of the list is).
   1885     int dist = -1;
   1886     QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
   1887 
   1888     if (dist >= 0) {
   1889         m_list[index] = val.value<T>();
   1890     }
   1891 }
   1892 
   1893 
   1894 template <typename T> JSValue QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
   1895 {
   1896     if (index < m_length) {
   1897         T val = m_list.at(index);
   1898         return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
   1899     }
   1900 
   1901     return jsUndefined();
   1902 }
   1903 
   1904 // ===============
   1905 
   1906 } }
   1907