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