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