Don't leak ScopeChainNode's
[qt:qt.git] / src / script / api / qscriptengine.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtScript module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file.  Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** If you have questions regarding the use of this file, please contact
19 ** Nokia at qt-info@nokia.com.
20 ** $QT_END_LICENSE$
21 **
22 ****************************************************************************/
23
24 #include "config.h"
25 #include "qscriptengine.h"
26 #include "qscriptsyntaxchecker_p.h"
27
28 #include "qscriptengine_p.h"
29 #include "qscriptengineagent_p.h"
30 #include "qscriptcontext_p.h"
31 #include "qscriptstring_p.h"
32 #include "qscriptvalue_p.h"
33 #include "qscriptvalueiterator.h"
34 #include "qscriptclass.h"
35 #include "qscriptcontextinfo.h"
36 #include "qscriptprogram.h"
37 #include "qscriptprogram_p.h"
38 #include "qdebug.h"
39
40 #include <QtCore/qstringlist.h>
41 #include <QtCore/qmetaobject.h>
42
43 #include <math.h>
44
45 #include "CodeBlock.h"
46 #include "Error.h"
47 #include "Interpreter.h"
48
49 #include "ExceptionHelpers.h"
50 #include "PrototypeFunction.h"
51 #include "InitializeThreading.h"
52 #include "ObjectPrototype.h"
53 #include "SourceCode.h"
54 #include "FunctionPrototype.h"
55 #include "TimeoutChecker.h"
56 #include "JSFunction.h"
57 #include "Parser.h"
58 #include "PropertyNameArray.h"
59 #include "Operations.h"
60
61 #include "bridge/qscriptfunction_p.h"
62 #include "bridge/qscriptclassobject_p.h"
63 #include "bridge/qscriptvariant_p.h"
64 #include "bridge/qscriptqobject_p.h"
65 #include "bridge/qscriptglobalobject_p.h"
66 #include "bridge/qscriptactivationobject_p.h"
67 #include "bridge/qscriptstaticscopeobject_p.h"
68
69 #ifndef QT_NO_QOBJECT
70 #include <QtCore/qcoreapplication.h>
71 #include <QtCore/qdir.h>
72 #include <QtCore/qfile.h>
73 #include <QtCore/qfileinfo.h>
74 #include <QtCore/qpluginloader.h>
75 #include <QtCore/qset.h>
76 #include <QtCore/qtextstream.h>
77 #include "qscriptextensioninterface.h"
78 #endif
79
80 Q_DECLARE_METATYPE(QScriptValue)
81 #ifndef QT_NO_QOBJECT
82 Q_DECLARE_METATYPE(QObjectList)
83 #endif
84 Q_DECLARE_METATYPE(QList<int>)
85
86 QT_BEGIN_NAMESPACE
87
88 /*!
89   \since 4.3
90   \class QScriptEngine
91   \reentrant
92
93   \brief The QScriptEngine class provides an environment for evaluating Qt Script code.
94
95   \ingroup script
96   \mainclass
97
98   See the \l{QtScript} documentation for information about the Qt Script language,
99   and how to get started with scripting your C++ application.
100
101   \section1 Evaluating Scripts
102
103   Use evaluate() to evaluate script code; this is the C++ equivalent
104   of the built-in script function \c{eval()}.
105
106   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 0
107
108   evaluate() returns a QScriptValue that holds the result of the
109   evaluation. The QScriptValue class provides functions for converting
110   the result to various C++ types (e.g. QScriptValue::toString()
111   and QScriptValue::toNumber()).
112
113   The following code snippet shows how a script function can be
114   defined and then invoked from C++ using QScriptValue::call():
115
116   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 1
117
118   As can be seen from the above snippets, a script is provided to the
119   engine in the form of a string. One common way of loading scripts is
120   by reading the contents of a file and passing it to evaluate():
121
122   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 2
123
124   Here we pass the name of the file as the second argument to
125   evaluate().  This does not affect evaluation in any way; the second
126   argument is a general-purpose string that is used to identify the
127   script for debugging purposes (for example, our filename will now
128   show up in any uncaughtExceptionBacktrace() involving the script).
129
130   \section1 Engine Configuration
131
132   The globalObject() function returns the \bold {Global Object}
133   associated with the script engine. Properties of the Global Object
134   are accessible from any script code (i.e. they are global
135   variables). Typically, before evaluating "user" scripts, you will
136   want to configure a script engine by adding one or more properties
137   to the Global Object:
138
139   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 3
140
141   Adding custom properties to the scripting environment is one of the
142   standard means of providing a scripting API that is specific to your
143   application. Usually these custom properties are objects created by
144   the newQObject() or newObject() functions, or constructor functions
145   created by newFunction().
146
147   \section1 Script Exceptions
148
149   evaluate() can throw a script exception (e.g. due to a syntax
150   error); in that case, the return value is the value that was thrown
151   (typically an \c{Error} object). You can check whether the
152   evaluation caused an exception by calling hasUncaughtException(). In
153   that case, you can call toString() on the error object to obtain an
154   error message. The current uncaught exception is also available
155   through uncaughtException().
156   Calling clearExceptions() will cause any uncaught exceptions to be
157   cleared.
158
159   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 4
160
161   The checkSyntax() function can be used to determine whether code can be
162   usefully passed to evaluate().
163
164   \section1 Script Object Creation
165
166   Use newObject() to create a standard Qt Script object; this is the
167   C++ equivalent of the script statement \c{new Object()}. You can use
168   the object-specific functionality in QScriptValue to manipulate the
169   script object (e.g. QScriptValue::setProperty()). Similarly, use
170   newArray() to create a Qt Script array object. Use newDate() to
171   create a \c{Date} object, and newRegExp() to create a \c{RegExp}
172   object.
173
174   \section1 QObject Integration
175
176   Use newQObject() to wrap a QObject (or subclass)
177   pointer. newQObject() returns a proxy script object; properties,
178   children, and signals and slots of the QObject are available as
179   properties of the proxy object. No binding code is needed because it
180   is done dynamically using the Qt meta object system.
181
182   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 5
183
184   Use qScriptConnect() to connect a C++ signal to a script function;
185   this is the Qt Script equivalent of QObject::connect().  When a
186   script function is invoked in response to a C++ signal, it can cause
187   a script exception; you can connect to the signalHandlerException()
188   signal to catch such an exception.
189
190   Use newQMetaObject() to wrap a QMetaObject; this gives you a "script
191   representation" of a QObject-based class. newQMetaObject() returns a
192   proxy script object; enum values of the class are available as
193   properties of the proxy object. You can also specify a function that
194   will be used to construct objects of the class (e.g.  when the
195   constructor is invoked from a script). For classes that have a
196   "standard" Qt constructor, Qt Script can provide a default script
197   constructor for you; see scriptValueFromQMetaObject().
198
199   See the \l{QtScript} documentation for more information on
200   the QObject integration.
201
202   \section1 Support for Custom C++ Types
203
204   Use newVariant() to wrap a QVariant. This can be used to store
205   values of custom (non-QObject) C++ types that have been registered
206   with the Qt meta-type system. To make such types scriptable, you
207   typically associate a prototype (delegate) object with the C++ type
208   by calling setDefaultPrototype(); the prototype object defines the
209   scripting API for the C++ type. Unlike the QObject integration,
210   there is no automatic binding possible here; i.e. you have to create
211   the scripting API yourself, for example by using the QScriptable
212   class.
213
214   Use fromScriptValue() to cast from a QScriptValue to another type,
215   and toScriptValue() to create a QScriptValue from another value.
216   You can specify how the conversion of C++ types is to be performed
217   with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType().
218   By default, Qt Script will use QVariant to store values of custom
219   types.
220
221   \section1 Importing Extensions
222
223   Use importExtension() to import plugin-based extensions into the
224   engine. Call availableExtensions() to obtain a list naming all the
225   available extensions, and importedExtensions() to obtain a list
226   naming only those extensions that have been imported.
227
228   Call pushContext() to open up a new variable scope, and popContext()
229   to close the current scope. This is useful if you are implementing
230   an extension that evaluates script code containing temporary
231   variable definitions (e.g. \c{var foo = 123;}) that are safe to
232   discard when evaluation has completed.
233
234   \section1 Native Functions
235
236   Use newFunction() to wrap native (C++) functions, including
237   constructors for your own custom types, so that these can be invoked
238   from script code. Such functions must have the signature
239   QScriptEngine::FunctionSignature. You may then pass the function as
240   argument to newFunction(). Here is an example of a function that
241   returns the sum of its first two arguments:
242
243   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 6
244
245   To expose this function to script code, you can set it as a property
246   of the Global Object:
247
248   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 7
249
250   Once this is done, script code can call your function in the exact
251   same manner as a "normal" script function:
252
253   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 8
254
255   \section1 Long-running Scripts
256
257   If you need to evaluate possibly long-running scripts from the main
258   (GUI) thread, you should first call setProcessEventsInterval() to
259   make sure that the GUI stays responsive. You can abort a currently
260   running script by calling abortEvaluation(). You can determine
261   whether an engine is currently running a script by calling
262   isEvaluating().
263
264   \section1 Garbage Collection
265
266   Qt Script objects may be garbage collected when they are no longer
267   referenced. There is no guarantee as to when automatic garbage
268   collection will take place.
269
270   The collectGarbage() function can be called to explicitly request
271   garbage collection.
272
273   The reportAdditionalMemoryCost() function can be called to indicate
274   that a Qt Script object occupies memory that isn't managed by the
275   scripting environment. Reporting the additional cost makes it more
276   likely that the garbage collector will be triggered. This can be
277   useful, for example, when many custom, native Qt Script objects are
278   allocated.
279
280   \section1 Core Debugging/Tracing Facilities
281
282   Since Qt 4.4, you can be notified of events pertaining to script
283   execution (e.g. script function calls and statement execution)
284   through the QScriptEngineAgent interface; see the setAgent()
285   function. This can be used to implement debugging and profiling of a
286   QScriptEngine.
287
288   \sa QScriptValue, QScriptContext, QScriptEngineAgent
289
290 */
291
292 /*!
293     \enum QScriptEngine::ValueOwnership
294
295     This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject().
296
297     \value QtOwnership The standard Qt ownership rules apply, i.e. the
298     associated object will never be explicitly deleted by the script
299     engine. This is the default. (QObject ownership is explained in
300     \l{Object Trees & Ownership}.)
301
302     \value ScriptOwnership The value is owned by the script
303     environment. The associated data will be deleted when appropriate
304     (i.e. after the garbage collector has discovered that there are no
305     more live references to the value).
306
307     \value AutoOwnership If the associated object has a parent, the Qt
308     ownership rules apply (QtOwnership); otherwise, the object is
309     owned by the script environment (ScriptOwnership).
310
311 */
312
313 /*!
314     \enum  QScriptEngine::QObjectWrapOption
315
316     These flags specify options when wrapping a QObject pointer with newQObject().
317
318     \value ExcludeChildObjects The script object will not expose child objects as properties.
319     \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass.
320     \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass.
321     \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties
322     \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot.
323     \value ExcludeSlots The script object will not expose the QObject's slots.
324     \value AutoCreateDynamicProperties Properties that don't already exist in the QObject will be created as dynamic properties of that object, rather than as properties of the script object.
325     \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object.
326     \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties.
327 */
328
329 class QScriptSyntaxCheckResultPrivate
330 {
331 public:
332     QScriptSyntaxCheckResultPrivate() { ref = 0; }
333     ~QScriptSyntaxCheckResultPrivate() {}
334
335     QScriptSyntaxCheckResult::State state;
336     int errorColumnNumber;
337     int errorLineNumber;
338     QString errorMessage;
339     QBasicAtomicInt ref;
340 };
341
342 class QScriptTypeInfo
343 {
344 public:
345     QScriptTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0)
346     { }
347
348     QByteArray signature;
349     QScriptEngine::MarshalFunction marshal;
350     QScriptEngine::DemarshalFunction demarshal;
351     JSC::JSValue prototype;
352 };
353
354 namespace QScript
355 {
356
357 static const qsreal D32 = 4294967296.0;
358
359 qint32 ToInt32(qsreal n)
360 {
361     if (qIsNaN(n) || qIsInf(n) || (n == 0))
362         return 0;
363
364     qsreal sign = (n < 0) ? -1.0 : 1.0;
365     qsreal abs_n = fabs(n);
366
367     n = ::fmod(sign * ::floor(abs_n), D32);
368     const double D31 = D32 / 2.0;
369
370     if (sign == -1 && n < -D31)
371         n += D32;
372
373     else if (sign != -1 && n >= D31)
374         n -= D32;
375
376     return qint32 (n);
377 }
378
379 quint32 ToUInt32(qsreal n)
380 {
381     if (qIsNaN(n) || qIsInf(n) || (n == 0))
382         return 0;
383
384     qsreal sign = (n < 0) ? -1.0 : 1.0;
385     qsreal abs_n = fabs(n);
386
387     n = ::fmod(sign * ::floor(abs_n), D32);
388
389     if (n < 0)
390         n += D32;
391
392     return quint32 (n);
393 }
394
395 quint16 ToUInt16(qsreal n)
396 {
397     static const qsreal D16 = 65536.0;
398
399     if (qIsNaN(n) || qIsInf(n) || (n == 0))
400         return 0;
401
402     qsreal sign = (n < 0) ? -1.0 : 1.0;
403     qsreal abs_n = fabs(n);
404
405     n = ::fmod(sign * ::floor(abs_n), D16);
406
407     if (n < 0)
408         n += D16;
409
410     return quint16 (n);
411 }
412
413 qsreal ToInteger(qsreal n)
414 {
415     if (qIsNaN(n))
416         return 0;
417
418     if (n == 0 || qIsInf(n))
419         return n;
420
421     int sign = n < 0 ? -1 : 1;
422     return sign * ::floor(::fabs(n));
423 }
424
425 #ifdef Q_CC_MSVC
426 // MSVC2008 crashes if these are inlined.
427
428 QString ToString(qsreal value)
429 {
430     return JSC::UString::from(value);
431 }
432
433 qsreal ToNumber(const QString &value)
434 {
435     return ((JSC::UString)value).toDouble();
436 }
437
438 #endif
439
440 static const qsreal MsPerSecond = 1000.0;
441
442 static inline int MsFromTime(qsreal t)
443 {
444     int r = int(::fmod(t, MsPerSecond));
445     return (r >= 0) ? r : r + int(MsPerSecond);
446 }
447
448 /*!
449   \internal
450   Converts a JS date value (milliseconds) to a QDateTime (local time).
451 */
452 QDateTime MsToDateTime(JSC::ExecState *exec, qsreal t)
453 {
454     if (qIsNaN(t))
455         return QDateTime();
456     JSC::GregorianDateTime tm;
457     JSC::msToGregorianDateTime(exec, t, /*output UTC=*/true, tm);
458     int ms = MsFromTime(t);
459     QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
460                                        QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
461     return convertedUTC.toLocalTime();
462 }
463
464 /*!
465   \internal
466   Converts a QDateTime to a JS date value (milliseconds).
467 */
468 qsreal DateTimeToMs(JSC::ExecState *exec, const QDateTime &dt)
469 {
470     if (!dt.isValid())
471         return qSNaN();
472     QDateTime utc = dt.toUTC();
473     QDate date = utc.date();
474     QTime time = utc.time();
475     JSC::GregorianDateTime tm;
476     tm.year = date.year() - 1900;
477     tm.month = date.month() - 1;
478     tm.monthDay = date.day();
479     tm.weekDay = date.dayOfWeek();
480     tm.yearDay = date.dayOfYear();
481     tm.hour = time.hour();
482     tm.minute = time.minute();
483     tm.second = time.second();
484     return JSC::gregorianDateTimeToMS(exec, tm, time.msec(), /*inputIsUTC=*/true);
485 }
486
487 void GlobalClientData::mark(JSC::MarkStack& markStack)
488 {
489     engine->mark(markStack);
490 }
491
492 class TimeoutCheckerProxy : public JSC::TimeoutChecker
493 {
494 public:
495     TimeoutCheckerProxy(const JSC::TimeoutChecker& originalChecker)
496         : JSC::TimeoutChecker(originalChecker)
497         , m_shouldProcessEvents(false)
498         , m_shouldAbortEvaluation(false)
499     {}
500
501     void setShouldProcessEvents(bool shouldProcess) { m_shouldProcessEvents = shouldProcess; }
502     void setShouldAbort(bool shouldAbort) { m_shouldAbortEvaluation = shouldAbort; }
503     bool shouldAbort() { return m_shouldAbortEvaluation; }
504
505     virtual bool didTimeOut(JSC::ExecState* exec)
506     {
507         if (JSC::TimeoutChecker::didTimeOut(exec))
508             return true;
509
510         if (m_shouldProcessEvents)
511             QCoreApplication::processEvents();
512
513         return m_shouldAbortEvaluation;
514     }
515
516 private:
517     bool m_shouldProcessEvents;
518     bool m_shouldAbortEvaluation;
519 };
520
521 static int toDigit(char c)
522 {
523     if ((c >= '0') && (c <= '9'))
524         return c - '0';
525     else if ((c >= 'a') && (c <= 'z'))
526         return 10 + c - 'a';
527     else if ((c >= 'A') && (c <= 'Z'))
528         return 10 + c - 'A';
529     return -1;
530 }
531
532 qsreal integerFromString(const char *buf, int size, int radix)
533 {
534     if (size == 0)
535         return qSNaN();
536
537     qsreal sign = 1.0;
538     int i = 0;
539     if (buf[0] == '+') {
540         ++i;
541     } else if (buf[0] == '-') {
542         sign = -1.0;
543         ++i;
544     }
545
546     if (((size-i) >= 2) && (buf[i] == '0')) {
547         if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
548             && (radix < 34)) {
549             if ((radix != 0) && (radix != 16))
550                 return 0;
551             radix = 16;
552             i += 2;
553         } else {
554             if (radix == 0) {
555                 radix = 8;
556                 ++i;
557             }
558         }
559     } else if (radix == 0) {
560         radix = 10;
561     }
562
563     int j = i;
564     for ( ; i < size; ++i) {
565         int d = toDigit(buf[i]);
566         if ((d == -1) || (d >= radix))
567             break;
568     }
569     qsreal result;
570     if (j == i) {
571         if (!qstrcmp(buf, "Infinity"))
572             result = qInf();
573         else
574             result = qSNaN();
575     } else {
576         result = 0;
577         qsreal multiplier = 1;
578         for (--i ; i >= j; --i, multiplier *= radix)
579             result += toDigit(buf[i]) * multiplier;
580     }
581     result *= sign;
582     return result;
583 }
584
585 qsreal integerFromString(const QString &str, int radix)
586 {
587     QByteArray ba = str.trimmed().toUtf8();
588     return integerFromString(ba.constData(), ba.size(), radix);
589 }
590
591 bool isFunction(JSC::JSValue value)
592 {
593     if (!value || !value.isObject())
594         return false;
595     JSC::CallData callData;
596     return (JSC::asObject(value)->getCallData(callData) != JSC::CallTypeNone);
597 }
598
599 static JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
600 static JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
601
602 JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
603 {
604 #ifndef QT_NO_QOBJECT
605     if (args.size() == 0) {
606         return JSC::throwError(exec, JSC::GeneralError, "Function.prototype.disconnect: no arguments given");
607     }
608
609     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
610         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: this object is not a signal");
611     }
612
613     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
614
615     const QMetaObject *meta = qtSignal->metaObject();
616     if (!meta) {
617         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.discconnect: cannot disconnect from deleted QObject");
618     }
619
620     QMetaMethod sig = meta->method(qtSignal->initialIndex());
621     if (sig.methodType() != QMetaMethod::Signal) {
622         QString message = QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
623                           .arg(QLatin1String(qtSignal->metaObject()->className()))
624                           .arg(QLatin1String(sig.signature()));
625         return JSC::throwError(exec, JSC::TypeError, message);
626     }
627
628     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
629
630     JSC::JSValue receiver;
631     JSC::JSValue slot;
632     JSC::JSValue arg0 = args.at(0);
633     if (args.size() < 2) {
634         slot = arg0;
635     } else {
636         receiver = arg0;
637         JSC::JSValue arg1 = args.at(1);
638         if (isFunction(arg1))
639             slot = arg1;
640         else {
641             QScript::SaveFrameHelper saveFrame(engine, exec);
642             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
643             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
644         }
645     }
646
647     if (!isFunction(slot)) {
648         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: target is not a function");
649     }
650
651     bool ok = engine->scriptDisconnect(thisObject, receiver, slot);
652     if (!ok) {
653         QString message = QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
654                           .arg(QLatin1String(qtSignal->metaObject()->className()))
655                           .arg(QLatin1String(sig.signature()));
656         return JSC::throwError(exec, JSC::GeneralError, message);
657     }
658     return JSC::jsUndefined();
659 #else
660     Q_UNUSED(eng);
661     return context->throwError(QScriptContext::TypeError,
662                                QLatin1String("Function.prototype.disconnect"));
663 #endif // QT_NO_QOBJECT
664 }
665
666 JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
667 {
668 #ifndef QT_NO_QOBJECT
669     if (args.size() == 0) {
670         return JSC::throwError(exec, JSC::GeneralError,"Function.prototype.connect: no arguments given");
671     }
672
673     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
674         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: this object is not a signal");
675     }
676
677     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
678
679     const QMetaObject *meta = qtSignal->metaObject();
680     if (!meta) {
681         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: cannot connect to deleted QObject");
682     }
683
684     QMetaMethod sig = meta->method(qtSignal->initialIndex());
685     if (sig.methodType() != QMetaMethod::Signal) {
686         QString message = QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
687                           .arg(QLatin1String(qtSignal->metaObject()->className()))
688                           .arg(QLatin1String(sig.signature()));
689         return JSC::throwError(exec, JSC::TypeError, message);
690     }
691
692     {
693         QList<int> overloads = qtSignal->overloadedIndexes();
694         if (!overloads.isEmpty()) {
695             overloads.append(qtSignal->initialIndex());
696             QByteArray signature = sig.signature();
697             QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
698                               .arg(QLatin1String(qtSignal->metaObject()->className()))
699                               .arg(QLatin1String(signature.left(signature.indexOf('('))));
700             for (int i = 0; i < overloads.size(); ++i) {
701                 QMetaMethod mtd = meta->method(overloads.at(i));
702                 message.append(QString::fromLatin1("    %0\n").arg(QString::fromLatin1(mtd.signature())));
703             }
704             message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
705                            .arg(QLatin1String(signature)));
706             return JSC::throwError(exec, JSC::GeneralError, message);
707         }
708     }
709
710     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
711
712     JSC::JSValue receiver;
713     JSC::JSValue slot;
714     JSC::JSValue arg0 = args.at(0);
715     if (args.size() < 2) {
716         slot = arg0;
717     } else {
718         receiver = arg0;
719         JSC::JSValue arg1 = args.at(1);
720         if (isFunction(arg1))
721             slot = arg1;
722         else {
723             QScript::SaveFrameHelper saveFrame(engine, exec);
724             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
725             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
726         }
727     }
728
729     if (!isFunction(slot)) {
730         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: target is not a function");
731     }
732
733     bool ok = engine->scriptConnect(thisObject, receiver, slot, Qt::AutoConnection);
734     if (!ok) {
735         QString message = QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
736                           .arg(QLatin1String(qtSignal->metaObject()->className()))
737                           .arg(QLatin1String(sig.signature()));
738         return JSC::throwError(exec, JSC::GeneralError, message);
739     }
740     return JSC::jsUndefined();
741 #else
742     Q_UNUSED(eng);
743     Q_UNUSED(classInfo);
744     return context->throwError(QScriptContext::TypeError,
745                                QLatin1String("Function.prototype.connect"));
746 #endif // QT_NO_QOBJECT
747 }
748
749 static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
750 static JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
751 static JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
752
753 JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList& args)
754 {
755     QString result;
756     for (unsigned i = 0; i < args.size(); ++i) {
757         if (i != 0)
758             result.append(QLatin1Char(' '));
759         QString s(args.at(i).toString(exec));
760         if (exec->hadException())
761             break;
762         result.append(s);
763     }
764     if (exec->hadException())
765         return exec->exception();
766     qDebug("%s", qPrintable(result));
767     return JSC::jsUndefined();
768 }
769
770 JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
771 {
772     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
773     engine->collectGarbage();
774     return JSC::jsUndefined();
775 }
776
777 JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
778 {
779     return JSC::JSValue(exec, 1);
780 }
781
782 static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
783 static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
784 static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
785 static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
786 static JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
787 static JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
788
789 JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
790 {
791     if (args.size() < 2)
792         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate() requires at least two arguments");
793     if (!args.at(0).isString())
794         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): first argument (context) must be a string");
795     if (!args.at(1).isString())
796         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): second argument (text) must be a string");
797     if ((args.size() > 2) && !args.at(2).isString())
798         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (comment) must be a string");
799     if ((args.size() > 3) && !args.at(3).isString())
800         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth argument (encoding) must be a string");
801     if ((args.size() > 4) && !args.at(4).isNumber())
802         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number");
803 #ifndef QT_NO_QOBJECT
804     JSC::UString context = args.at(0).toString(exec);
805 #endif
806     JSC::UString text = args.at(1).toString(exec);
807 #ifndef QT_NO_QOBJECT
808     JSC::UString comment;
809     if (args.size() > 2)
810         comment = args.at(2).toString(exec);
811     QCoreApplication::Encoding encoding = QCoreApplication::CodecForTr;
812     if (args.size() > 3) {
813         JSC::UString encStr = args.at(3).toString(exec);
814         if (encStr == "CodecForTr")
815             encoding = QCoreApplication::CodecForTr;
816         else if (encStr == "UnicodeUTF8")
817             encoding = QCoreApplication::UnicodeUTF8;
818         else
819             return JSC::throwError(exec, JSC::GeneralError, QString::fromLatin1("qsTranslate(): invalid encoding '%0'").arg(encStr));
820     }
821     int n = -1;
822     if (args.size() > 4)
823         n = args.at(4).toInt32(exec);
824 #endif
825     JSC::UString result;
826 #ifndef QT_NO_QOBJECT
827     result = QCoreApplication::translate(QScript::convertToLatin1(context).constData(),
828                                          QScript::convertToLatin1(text).constData(),
829                                          QScript::convertToLatin1(comment).constData(),
830                                          encoding, n);
831 #else
832     result = text;
833 #endif
834     return JSC::jsString(exec, result);
835 }
836
837 JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
838 {
839     if (args.size() < 2)
840         return JSC::jsUndefined();
841     return args.at(1);
842 }
843
844 JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
845 {
846     if (args.size() < 1)
847         return JSC::throwError(exec, JSC::GeneralError, "qsTr() requires at least one argument");
848     if (!args.at(0).isString())
849         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): first argument (text) must be a string");
850     if ((args.size() > 1) && !args.at(1).isString())
851         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
852     if ((args.size() > 2) && !args.at(2).isNumber())
853         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): third argument (n) must be a number");
854 #ifndef QT_NO_QOBJECT
855     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
856     JSC::UString context;
857     // The first non-empty source URL in the call stack determines the translation context.
858     {
859         JSC::ExecState *frame = exec->callerFrame()->removeHostCallFrameFlag();
860         while (frame) {
861             if (frame->codeBlock() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)
862                 && frame->codeBlock()->source()
863                 && !frame->codeBlock()->source()->url().isEmpty()) {
864                 context = engine->translationContextFromUrl(frame->codeBlock()->source()->url());
865                 break;
866             }
867             frame = frame->callerFrame()->removeHostCallFrameFlag();
868         }
869     }
870 #endif
871     JSC::UString text = args.at(0).toString(exec);
872 #ifndef QT_NO_QOBJECT
873     JSC::UString comment;
874     if (args.size() > 1)
875         comment = args.at(1).toString(exec);
876     int n = -1;
877     if (args.size() > 2)
878         n = args.at(2).toInt32(exec);
879 #endif
880     JSC::UString result;
881 #ifndef QT_NO_QOBJECT
882     result = QCoreApplication::translate(QScript::convertToLatin1(context).constData(),
883                                          QScript::convertToLatin1(text).constData(),
884                                          QScript::convertToLatin1(comment).constData(),
885                                          QCoreApplication::CodecForTr, n);
886 #else
887     result = text;
888 #endif
889     return JSC::jsString(exec, result);
890 }
891
892 JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
893 {
894     if (args.size() < 1)
895         return JSC::jsUndefined();
896     return args.at(0);
897 }
898
899 JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
900 {
901     if (args.size() < 1)
902         return JSC::throwError(exec, JSC::GeneralError, "qsTrId() requires at least one argument");
903     if (!args.at(0).isString())
904         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): first argument (id) must be a string");
905     if ((args.size() > 1) && !args.at(1).isNumber())
906         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): second argument (n) must be a number");
907     JSC::UString id = args.at(0).toString(exec);
908     int n = -1;
909     if (args.size() > 1)
910         n = args.at(1).toInt32(exec);
911     return JSC::jsString(exec, qtTrId(QScript::convertToLatin1(id).constData(), n));
912 }
913
914 JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
915 {
916     if (args.size() < 1)
917         return JSC::jsUndefined();
918     return args.at(0);
919 }
920
921 static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
922
923 JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args)
924 {
925     QString value(thisObject.toString(exec));
926     JSC::JSValue arg = (args.size() != 0) ? args.at(0) : JSC::jsUndefined();
927     QString result;
928     if (arg.isString())
929         result = value.arg(arg.toString(exec));
930     else if (arg.isNumber())
931         result = value.arg(arg.toNumber(exec));
932     return JSC::jsString(exec, result);
933 }
934
935
936 #if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
937 static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng)
938 {
939     QString path = ctx->argument(0).toString();
940     QStringList components = path.split(QLatin1Char('.'));
941     QScriptValue o = eng->globalObject();
942     for (int i = 0; i < components.count(); ++i) {
943         QString name = components.at(i);
944         QScriptValue oo = o.property(name);
945         if (!oo.isValid()) {
946             oo = eng->newObject();
947             o.setProperty(name, oo);
948         }
949         o = oo;
950     }
951     return o;
952 }
953 #endif
954
955 } // namespace QScript
956
957 QScriptEnginePrivate::QScriptEnginePrivate()
958     : registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0),
959       registeredScriptStrings(0), inEval(false)
960 {
961     qMetaTypeId<QScriptValue>();
962     qMetaTypeId<QList<int> >();
963 #ifndef QT_NO_QOBJECT
964     qMetaTypeId<QObjectList>();
965 #endif
966
967     if (!QCoreApplication::instance()) {
968         qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
969         return;
970     }
971     JSC::initializeThreading();
972     JSC::IdentifierTable *oldTable = JSC::currentIdentifierTable();
973     globalData = JSC::JSGlobalData::create().releaseRef();
974     globalData->clientData = new QScript::GlobalClientData(this);
975     JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
976
977     JSC::ExecState* exec = globalObject->globalExec();
978
979     scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
980     staticScopeObjectStructure = QScriptStaticScopeObject::createStructure(JSC::jsNull());
981
982     qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
983     qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
984
985     qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
986     qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
987
988     variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
989     variantWrapperObjectStructure = QScriptObject::createStructure(variantPrototype);
990
991     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
992     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
993     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
994
995     // ### rather than extending Function.prototype, consider creating a QtSignal.prototype
996     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "disconnect"), QScript::functionDisconnect));
997     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "connect"), QScript::functionConnect));
998
999     JSC::TimeoutChecker* originalChecker = globalData->timeoutChecker;
1000     globalData->timeoutChecker = new QScript::TimeoutCheckerProxy(*originalChecker);
1001     delete originalChecker;
1002
1003     currentFrame = exec;
1004
1005     originalGlobalObjectProxy = 0;
1006     activeAgent = 0;
1007     agentLineNumber = -1;
1008     processEventsInterval = -1;
1009     cachedTranslationUrl = JSC::UString();
1010     cachedTranslationContext = JSC::UString();
1011     JSC::setCurrentIdentifierTable(oldTable);
1012 }
1013
1014 QScriptEnginePrivate::~QScriptEnginePrivate()
1015 {
1016     QScript::APIShim shim(this);
1017
1018     //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
1019     QHash<intptr_t,QScript::UStringSourceProviderWithFeedback*>::const_iterator it;
1020     for (it = loadedScripts.constBegin(); it != loadedScripts.constEnd(); ++it)
1021         it.value()->disconnectFromEngine();
1022
1023     while (!ownedAgents.isEmpty())
1024         delete ownedAgents.takeFirst();
1025
1026     detachAllRegisteredScriptPrograms();
1027     detachAllRegisteredScriptValues();
1028     detachAllRegisteredScriptStrings();
1029     qDeleteAll(m_qobjectData);
1030     qDeleteAll(m_typeInfos);
1031     globalData->heap.destroy();
1032     globalData->deref();
1033     while (freeScriptValues) {
1034         QScriptValuePrivate *p = freeScriptValues;
1035         freeScriptValues = p->next;
1036         qFree(p);
1037     }
1038 }
1039
1040 QVariant QScriptEnginePrivate::jscValueToVariant(JSC::ExecState *exec, JSC::JSValue value, int targetType)
1041 {
1042     QVariant v(targetType, (void *)0);
1043     if (convertValue(exec, value, targetType, v.data()))
1044         return v;
1045     if (uint(targetType) == QVariant::LastType)
1046         return toVariant(exec, value);
1047     if (isVariant(value)) {
1048         v = variantValue(value);
1049         if (v.canConvert(QVariant::Type(targetType))) {
1050             v.convert(QVariant::Type(targetType));
1051             return v;
1052         }
1053         QByteArray typeName = v.typeName();
1054         if (typeName.endsWith('*')
1055             && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
1056             return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
1057         }
1058     }
1059     return QVariant();
1060 }
1061
1062 JSC::JSValue QScriptEnginePrivate::arrayFromStringList(JSC::ExecState *exec, const QStringList &lst)
1063 {
1064     JSC::JSValue arr =  newArray(exec, lst.size());
1065     for (int i = 0; i < lst.size(); ++i)
1066         setProperty(exec, arr, i, JSC::jsString(exec, lst.at(i)));
1067     return arr;
1068 }
1069
1070 QStringList QScriptEnginePrivate::stringListFromArray(JSC::ExecState *exec, JSC::JSValue arr)
1071 {
1072     QStringList lst;
1073     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1074     for (uint i = 0; i < len; ++i)
1075         lst.append(toString(exec, property(exec, arr, i)));
1076     return lst;
1077 }
1078
1079 JSC::JSValue QScriptEnginePrivate::arrayFromVariantList(JSC::ExecState *exec, const QVariantList &lst)
1080 {
1081     JSC::JSValue arr = newArray(exec, lst.size());
1082     for (int i = 0; i < lst.size(); ++i)
1083         setProperty(exec, arr, i, jscValueFromVariant(exec, lst.at(i)));
1084     return arr;
1085 }
1086
1087 QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSArray *arr)
1088 {
1089     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1090     if (eng->visitedConversionObjects.contains(arr))
1091         return QVariantList(); // Avoid recursion.
1092     eng->visitedConversionObjects.insert(arr);
1093     QVariantList lst;
1094     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1095     for (uint i = 0; i < len; ++i)
1096         lst.append(toVariant(exec, property(exec, arr, i)));
1097     eng->visitedConversionObjects.remove(arr);
1098     return lst;
1099 }
1100
1101 JSC::JSValue QScriptEnginePrivate::objectFromVariantMap(JSC::ExecState *exec, const QVariantMap &vmap)
1102 {
1103     JSC::JSValue obj = JSC::constructEmptyObject(exec);
1104     QVariantMap::const_iterator it;
1105     for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1106         setProperty(exec, obj, it.key(), jscValueFromVariant(exec, it.value()));
1107     return obj;
1108 }
1109
1110 QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSObject *obj)
1111 {
1112     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1113     if (eng->visitedConversionObjects.contains(obj))
1114         return QVariantMap(); // Avoid recursion.
1115     eng->visitedConversionObjects.insert(obj);
1116     JSC::PropertyNameArray propertyNames(exec);
1117     obj->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
1118     QVariantMap vmap;
1119     JSC::PropertyNameArray::const_iterator it = propertyNames.begin();
1120     for( ; it != propertyNames.end(); ++it)
1121         vmap.insert(it->ustring(), toVariant(exec, property(exec, obj, *it)));
1122     eng->visitedConversionObjects.remove(obj);
1123     return vmap;
1124 }
1125
1126 JSC::JSValue QScriptEnginePrivate::defaultPrototype(int metaTypeId) const
1127 {
1128     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1129     if (!info)
1130         return JSC::JSValue();
1131     return info->prototype;
1132 }
1133
1134 void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, JSC::JSValue prototype)
1135 {
1136     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1137     if (!info) {
1138         info = new QScriptTypeInfo();
1139         m_typeInfos.insert(metaTypeId, info);
1140     }
1141     info->prototype = prototype;
1142 }
1143
1144 JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const
1145 {
1146     return globalData->head;
1147 }
1148
1149 JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const
1150 {
1151     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1152     return glob->customGlobalObject;
1153 }
1154
1155 JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy()
1156 {
1157     if (!originalGlobalObjectProxy) {
1158         JSC::ExecState* exec = currentFrame;
1159         originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1160     }
1161     return originalGlobalObjectProxy;
1162 }
1163
1164 JSC::JSObject *QScriptEnginePrivate::globalObject() const
1165 {
1166     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1167     if (glob->customGlobalObject)
1168         return glob->customGlobalObject;
1169     return glob;
1170 }
1171
1172 void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object)
1173 {
1174     if (object == globalObject())
1175         return;
1176     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1177     if (object == originalGlobalObjectProxy) {
1178         glob->customGlobalObject = 0;
1179         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1180         glob->setPrototype(originalGlobalObjectProxy->prototype());
1181     } else {
1182         Q_ASSERT(object != originalGlobalObject());
1183         glob->customGlobalObject = object;
1184         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1185         glob->setPrototype(object->prototype());
1186     }
1187 }
1188
1189 /*!
1190   \internal
1191
1192   If the given \a value is the original global object, returns the custom
1193   global object or a proxy to the original global object; otherwise returns \a
1194   value.
1195 */
1196 JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value)
1197 {
1198     if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject())
1199         return value;
1200     Q_ASSERT(JSC::asObject(value) == originalGlobalObject());
1201     if (customGlobalObject())
1202         return customGlobalObject();
1203     if (!originalGlobalObjectProxy)
1204         originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1205     return originalGlobalObjectProxy;
1206 }
1207 /*!
1208     \internal
1209     Return the 'this' value for a given context
1210 */
1211 JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame)
1212 {
1213     if (frame->codeBlock() != 0) {
1214         return frame->thisValue();
1215     } else if(frame == frame->lexicalGlobalObject()->globalExec()) {
1216         return frame->globalThisValue();
1217     } else {
1218         JSC::Register *thisRegister = thisRegisterForFrame(frame);
1219         return thisRegister->jsValue();
1220     }
1221 }
1222
1223 JSC::Register* QScriptEnginePrivate::thisRegisterForFrame(JSC::ExecState *frame)
1224 {
1225     Q_ASSERT(frame->codeBlock() == 0); // only for native calls
1226     return frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
1227 }
1228
1229 /*! \internal
1230      For native context, we use the ReturnValueRegister entry in the stackframe header to store flags.
1231      We can do that because this header is not used as the native function return their value thought C++
1232
1233      when setting flags, NativeContext should always be set
1234
1235      contextFlags returns 0 for non native context
1236  */
1237 uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec)
1238 {
1239     if (exec->codeBlock())
1240         return 0; //js function doesn't have flags
1241
1242     return exec->returnValueRegister();
1243 }
1244
1245 void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
1246 {
1247     Q_ASSERT(!exec->codeBlock());
1248     exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::Register::withInt(flags);
1249 }
1250
1251
1252 void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
1253 {
1254     Q_Q(QScriptEngine);
1255
1256     markStack.append(originalGlobalObject());
1257     markStack.append(globalObject());
1258     if (originalGlobalObjectProxy)
1259         markStack.append(originalGlobalObjectProxy);
1260
1261     if (qobjectPrototype)
1262         markStack.append(qobjectPrototype);
1263     if (qmetaobjectPrototype)
1264         markStack.append(qmetaobjectPrototype);
1265     if (variantPrototype)
1266         markStack.append(variantPrototype);
1267
1268     {
1269         QScriptValuePrivate *it;
1270         for (it = registeredScriptValues; it != 0; it = it->next) {
1271             if (it->isJSC())
1272                 markStack.append(it->jscValue);
1273         }
1274     }
1275
1276     {
1277         QHash<int, QScriptTypeInfo*>::const_iterator it;
1278         for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
1279             if ((*it)->prototype)
1280                 markStack.append((*it)->prototype);
1281         }
1282     }
1283
1284     {
1285         QScriptContext *context = q->currentContext();
1286
1287         while (context) {
1288             JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
1289             JSC::ScopeChainIterator it(node);
1290             for (it = node->begin(); it != node->end(); ++it) {
1291                 JSC::JSObject *object = *it;
1292                 if (object)
1293                     markStack.append(object);
1294             }
1295
1296             context = context->parentContext();
1297         }
1298     }
1299
1300 #ifndef QT_NO_QOBJECT
1301     markStack.drain(); // make sure everything is marked before marking qobject data
1302     {
1303         QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1304         for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1305             QScript::QObjectData *qdata = it.value();
1306             qdata->mark(markStack);
1307         }
1308     }
1309 #endif
1310 }
1311
1312 bool QScriptEnginePrivate::isCollecting() const
1313 {
1314     return globalData->heap.isBusy();
1315 }
1316
1317 void QScriptEnginePrivate::collectGarbage()
1318 {
1319     QScript::APIShim shim(this);
1320     globalData->heap.collectAllGarbage();
1321 }
1322
1323 void QScriptEnginePrivate::reportAdditionalMemoryCost(int size)
1324 {
1325     if (size > 0)
1326         globalData->heap.reportExtraMemoryCost(size);
1327 }
1328
1329 QScript::TimeoutCheckerProxy *QScriptEnginePrivate::timeoutChecker() const
1330 {
1331     return static_cast<QScript::TimeoutCheckerProxy*>(globalData->timeoutChecker);
1332 }
1333
1334 void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
1335 {
1336     ownedAgents.removeOne(agent);
1337     if (activeAgent == agent) {
1338         QScriptEngineAgentPrivate::get(agent)->detach();
1339         activeAgent = 0;
1340     }
1341 }
1342
1343 JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
1344                                                   JSC::EvalExecutable *executable,
1345                                                   bool &compile)
1346 {
1347     Q_Q(QScriptEngine);
1348     QBoolBlocker inEvalBlocker(inEval, true);
1349     q->currentContext()->activationObject(); //force the creation of a context for native function;
1350
1351     JSC::Debugger* debugger = originalGlobalObject()->debugger();
1352     if (debugger)
1353         debugger->evaluateStart(sourceId);
1354
1355     q->clearExceptions();
1356     JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject);
1357
1358     if (compile) {
1359         JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
1360         if (error) {
1361             compile = false;
1362             exec->setException(error);
1363
1364             if (debugger) {
1365                 debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
1366                 debugger->evaluateStop(error, sourceId);
1367             }
1368
1369             return error;
1370         }
1371     }
1372
1373     JSC::JSValue thisValue = thisForContext(exec);
1374     JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
1375                                 ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
1376     JSC::JSValue exceptionValue;
1377     timeoutChecker()->setShouldAbort(false);
1378     if (processEventsInterval > 0)
1379         timeoutChecker()->reset();
1380
1381     JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
1382
1383     if (timeoutChecker()->shouldAbort()) {
1384         if (abortResult.isError())
1385             exec->setException(scriptValueToJSCValue(abortResult));
1386
1387         if (debugger)
1388             debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
1389
1390         return scriptValueToJSCValue(abortResult);
1391     }
1392
1393     if (exceptionValue) {
1394         exec->setException(exceptionValue);
1395
1396         if (debugger)
1397             debugger->evaluateStop(exceptionValue, sourceId);
1398
1399         return exceptionValue;
1400     }
1401
1402     if (debugger)
1403         debugger->evaluateStop(result, sourceId);
1404
1405     Q_ASSERT(!exec->hadException());
1406     return result;
1407 }
1408
1409 #ifndef QT_NO_QOBJECT
1410
1411 JSC::JSValue QScriptEnginePrivate::newQObject(
1412     QObject *object, QScriptEngine::ValueOwnership ownership,
1413     const QScriptEngine::QObjectWrapOptions &options)
1414 {
1415     if (!object)
1416         return JSC::jsNull();
1417     JSC::ExecState* exec = currentFrame;
1418     QScript::QObjectData *data = qobjectData(object);
1419     bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
1420     QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
1421     QScriptObject *result = 0;
1422     if (preferExisting) {
1423         result = data->findWrapper(ownership, opt);
1424         if (result)
1425             return result;
1426     }
1427     result = new (exec) QScriptObject(qobjectWrapperObjectStructure);
1428     if (preferExisting)
1429         data->registerWrapper(result, ownership, opt);
1430     result->setDelegate(new QScript::QObjectDelegate(object, ownership, options));
1431     /*if (setDefaultPrototype)*/ {
1432         const QMetaObject *meta = object->metaObject();
1433         while (meta) {
1434             QByteArray typeString = meta->className();
1435             typeString.append('*');
1436             int typeId = QMetaType::type(typeString);
1437             if (typeId != 0) {
1438                 JSC::JSValue proto = defaultPrototype(typeId);
1439                 if (proto) {
1440                     result->setPrototype(proto);
1441                     break;
1442                 }
1443             }
1444             meta = meta->superClass();
1445         }
1446     }
1447     return result;
1448 }
1449
1450 JSC::JSValue QScriptEnginePrivate::newQMetaObject(
1451     const QMetaObject *metaObject, JSC::JSValue ctor)
1452 {
1453     if (!metaObject)
1454         return JSC::jsNull();
1455     JSC::ExecState* exec = currentFrame;
1456     QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
1457     return result;
1458 }
1459
1460 bool QScriptEnginePrivate::convertToNativeQObject(JSC::ExecState *exec, JSC::JSValue value,
1461                                                   const QByteArray &targetType,
1462                                                   void **result)
1463 {
1464     if (!targetType.endsWith('*'))
1465         return false;
1466     if (QObject *qobject = toQObject(exec, value)) {
1467         int start = targetType.startsWith("const ") ? 6 : 0;
1468         QByteArray className = targetType.mid(start, targetType.size()-start-1);
1469         if (void *instance = qobject->qt_metacast(className)) {
1470             *result = instance;
1471             return true;
1472         }
1473     }
1474     return false;
1475 }
1476
1477 QScript::QObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
1478 {
1479     QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1480     it = m_qobjectData.constFind(object);
1481     if (it != m_qobjectData.constEnd())
1482         return it.value();
1483
1484     QScript::QObjectData *data = new QScript::QObjectData(this);
1485     m_qobjectData.insert(object, data);
1486     QObject::connect(object, SIGNAL(destroyed(QObject*)),
1487                      q_func(), SLOT(_q_objectDestroyed(QObject*)));
1488     return data;
1489 }
1490
1491 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
1492 {
1493     QHash<QObject*, QScript::QObjectData*>::iterator it;
1494     it = m_qobjectData.find(object);
1495     Q_ASSERT(it != m_qobjectData.end());
1496     QScript::QObjectData *data = it.value();
1497     m_qobjectData.erase(it);
1498     delete data;
1499 }
1500
1501 void QScriptEnginePrivate::disposeQObject(QObject *object)
1502 {
1503     // TODO
1504 /*    if (isCollecting()) {
1505         // wait until we're done with GC before deleting it
1506         int index = m_qobjectsToBeDeleted.indexOf(object);
1507         if (index == -1)
1508             m_qobjectsToBeDeleted.append(object);
1509             } else*/ {
1510         delete object;
1511     }
1512 }
1513
1514 void QScriptEnginePrivate::emitSignalHandlerException()
1515 {
1516     Q_Q(QScriptEngine);
1517     emit q->signalHandlerException(q->uncaughtException());
1518 }
1519
1520 bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
1521                                          JSC::JSValue receiver, JSC::JSValue function,
1522                                          Qt::ConnectionType type)
1523 {
1524     Q_ASSERT(sender);
1525     Q_ASSERT(signal);
1526     const QMetaObject *meta = sender->metaObject();
1527     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1528     if (index == -1)
1529         return false;
1530     return scriptConnect(sender, index, receiver, function, /*wrapper=*/JSC::JSValue(), type);
1531 }
1532
1533 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
1534                                             JSC::JSValue receiver, JSC::JSValue function)
1535 {
1536     Q_ASSERT(sender);
1537     Q_ASSERT(signal);
1538     const QMetaObject *meta = sender->metaObject();
1539     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1540     if (index == -1)
1541         return false;
1542     return scriptDisconnect(sender, index, receiver, function);
1543 }
1544
1545 bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
1546                                          JSC::JSValue receiver, JSC::JSValue function,
1547                                          JSC::JSValue senderWrapper,
1548                                          Qt::ConnectionType type)
1549 {
1550     QScript::QObjectData *data = qobjectData(sender);
1551     return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
1552 }
1553
1554 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
1555                                             JSC::JSValue receiver, JSC::JSValue function)
1556 {
1557     QScript::QObjectData *data = qobjectData(sender);
1558     if (!data)
1559         return false;
1560     return data->removeSignalHandler(sender, signalIndex, receiver, function);
1561 }
1562
1563 bool QScriptEnginePrivate::scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
1564                                          JSC::JSValue function, Qt::ConnectionType type)
1565 {
1566     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1567     int index = fun->mostGeneralMethod();
1568     return scriptConnect(fun->qobject(), index, receiver, function, fun->wrapperObject(), type);
1569 }
1570
1571 bool QScriptEnginePrivate::scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
1572                                             JSC::JSValue function)
1573 {
1574     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1575     int index = fun->mostGeneralMethod();
1576     return scriptDisconnect(fun->qobject(), index, receiver, function);
1577 }
1578
1579 #endif
1580
1581 void QScriptEnginePrivate::detachAllRegisteredScriptPrograms()
1582 {
1583     QSet<QScriptProgramPrivate*>::const_iterator it;
1584     for (it = registeredScriptPrograms.constBegin(); it != registeredScriptPrograms.constEnd(); ++it)
1585         (*it)->detachFromEngine();
1586     registeredScriptPrograms.clear();
1587 }
1588
1589 void QScriptEnginePrivate::detachAllRegisteredScriptValues()
1590 {
1591     QScriptValuePrivate *it;
1592     QScriptValuePrivate *next;
1593     for (it = registeredScriptValues; it != 0; it = next) {
1594         it->detachFromEngine();
1595         next = it->next;
1596         it->prev = 0;
1597         it->next = 0;
1598     }
1599     registeredScriptValues = 0;
1600 }
1601
1602 void QScriptEnginePrivate::detachAllRegisteredScriptStrings()
1603 {
1604     QScriptStringPrivate *it;
1605     QScriptStringPrivate *next;
1606     for (it = registeredScriptStrings; it != 0; it = next) {
1607         it->detachFromEngine();
1608         next = it->next;
1609         it->prev = 0;
1610         it->next = 0;
1611     }
1612     registeredScriptStrings = 0;
1613 }
1614
1615 #ifndef QT_NO_REGEXP
1616
1617 Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
1618
1619 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QRegExp &regexp)
1620 {
1621     JSC::JSValue buf[2];
1622     JSC::ArgList args(buf, sizeof(buf));
1623
1624     //convert the pattern to a ECMAScript pattern
1625     QString pattern = qt_regexp_toCanonical(regexp.pattern(), regexp.patternSyntax());
1626     if (regexp.isMinimal()) {
1627         QString ecmaPattern;
1628         int len = pattern.length();
1629         ecmaPattern.reserve(len);
1630         int i = 0;
1631         const QChar *wc = pattern.unicode();
1632         bool inBracket = false;
1633         while (i < len) {
1634             QChar c = wc[i++];
1635             ecmaPattern += c;
1636             switch (c.unicode()) {
1637             case '?':
1638             case '+':
1639             case '*':
1640             case '}':
1641                 if (!inBracket)
1642                     ecmaPattern += QLatin1Char('?');
1643                 break;
1644             case '\\':
1645                 if (i < len)
1646                     ecmaPattern += wc[i++];
1647                 break;
1648             case '[':
1649                 inBracket = true;
1650                 break;
1651             case ']':
1652                 inBracket = false;
1653                break;
1654             default:
1655                 break;
1656             }
1657         }
1658         pattern = ecmaPattern;
1659     }
1660
1661     JSC::UString jscPattern = pattern;
1662     QString flags;
1663     if (regexp.caseSensitivity() == Qt::CaseInsensitive)
1664         flags.append(QLatin1Char('i'));
1665     JSC::UString jscFlags = flags;
1666     buf[0] = JSC::jsString(exec, jscPattern);
1667     buf[1] = JSC::jsString(exec, jscFlags);
1668     return JSC::constructRegExp(exec, args);
1669 }
1670
1671 #endif
1672
1673 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QString &pattern, const QString &flags)
1674 {
1675     JSC::JSValue buf[2];
1676     JSC::ArgList args(buf, sizeof(buf));
1677     JSC::UString jscPattern = pattern;
1678     QString strippedFlags;
1679     if (flags.contains(QLatin1Char('i')))
1680         strippedFlags += QLatin1Char('i');
1681     if (flags.contains(QLatin1Char('m')))
1682         strippedFlags += QLatin1Char('m');
1683     if (flags.contains(QLatin1Char('g')))
1684         strippedFlags += QLatin1Char('g');
1685     JSC::UString jscFlags = strippedFlags;
1686     buf[0] = JSC::jsString(exec, jscPattern);
1687     buf[1] = JSC::jsString(exec, jscFlags);
1688     return JSC::constructRegExp(exec, args);
1689 }
1690
1691 JSC::JSValue QScriptEnginePrivate::newVariant(const QVariant &value)
1692 {
1693     QScriptObject *obj = new (currentFrame) QScriptObject(variantWrapperObjectStructure);
1694     obj->setDelegate(new QScript::QVariantDelegate(value));
1695     JSC::JSValue proto = defaultPrototype(value.userType());
1696     if (proto)
1697         obj->setPrototype(proto);
1698     return obj;
1699 }
1700
1701 JSC::JSValue QScriptEnginePrivate::newVariant(JSC::JSValue objectValue,
1702                                               const QVariant &value)
1703 {
1704     if (!isObject(objectValue))
1705         return newVariant(value);
1706     JSC::JSObject *jscObject = JSC::asObject(objectValue);
1707     if (!jscObject->inherits(&QScriptObject::info)) {
1708         qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
1709         return JSC::JSValue();
1710     }
1711     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
1712     if (!isVariant(objectValue)) {
1713         jscScriptObject->setDelegate(new QScript::QVariantDelegate(value));
1714     } else {
1715         setVariantValue(objectValue, value);
1716     }
1717     return objectValue;
1718 }
1719
1720 #ifndef QT_NO_REGEXP
1721
1722 QRegExp QScriptEnginePrivate::toRegExp(JSC::ExecState *exec, JSC::JSValue value)
1723 {
1724     if (!isRegExp(value))
1725         return QRegExp();
1726     QString pattern = toString(exec, property(exec, value, "source", QScriptValue::ResolvePrototype));
1727     Qt::CaseSensitivity kase = Qt::CaseSensitive;
1728     if (toBool(exec, property(exec, value, "ignoreCase", QScriptValue::ResolvePrototype)))
1729         kase = Qt::CaseInsensitive;
1730     return QRegExp(pattern, kase, QRegExp::RegExp2);
1731 }
1732
1733 #endif
1734
1735 QVariant QScriptEnginePrivate::toVariant(JSC::ExecState *exec, JSC::JSValue value)
1736 {
1737     if (!value) {
1738         return QVariant();
1739     } else if (isObject(value)) {
1740         if (isVariant(value))
1741             return variantValue(value);
1742 #ifndef QT_NO_QOBJECT
1743         else if (isQObject(value))
1744             return qVariantFromValue(toQObject(exec, value));
1745 #endif
1746         else if (isDate(value))
1747             return QVariant(toDateTime(exec, value));
1748 #ifndef QT_NO_REGEXP
1749         else if (isRegExp(value))
1750             return QVariant(toRegExp(exec, value));
1751 #endif
1752         else if (isArray(value))
1753             return variantListFromArray(exec, JSC::asArray(value));
1754         else if (QScriptDeclarativeClass *dc = declarativeClass(value))
1755             return dc->toVariant(declarativeObject(value));
1756         return variantMapFromObject(exec, JSC::asObject(value));
1757     } else if (value.isNumber()) {
1758         return QVariant(toNumber(exec, value));
1759     } else if (value.isString()) {
1760         return QVariant(toString(exec, value));
1761     } else if (value.isBoolean()) {
1762         return QVariant(toBool(exec, value));
1763     }
1764     return QVariant();
1765 }
1766
1767 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id, int resolveMode)
1768 {
1769     JSC::JSValue result;
1770     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1771         // Look in the object's own properties
1772         JSC::JSObject *object = JSC::asObject(value);
1773         JSC::PropertySlot slot(object);
1774         if (object->getOwnPropertySlot(exec, id, slot))
1775             result = slot.getValue(exec, id);
1776     }
1777     if (!result && (resolveMode & QScriptValue::ResolveScope)) {
1778         // ### check if it's a function object and look in the scope chain
1779         JSC::JSValue scope = property(exec, value, "__qt_scope__", QScriptValue::ResolveLocal);
1780         if (isObject(scope))
1781             result = property(exec, scope, id, resolveMode);
1782     }
1783     return result;
1784 }
1785
1786 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, quint32 index, int resolveMode)
1787 {
1788     JSC::JSValue result;
1789     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1790         // Look in the object's own properties
1791         JSC::JSObject *object = JSC::asObject(value);
1792         JSC::PropertySlot slot(object);
1793         if (object->getOwnPropertySlot(exec, index, slot))
1794             result = slot.getValue(exec, index);
1795     }
1796     return result;
1797 }
1798
1799 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, const JSC::Identifier &id,
1800                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1801 {
1802     JSC::JSObject *thisObject = JSC::asObject(objectValue);
1803     JSC::JSValue setter = thisObject->lookupSetter(exec, id);
1804     JSC::JSValue getter = thisObject->lookupGetter(exec, id);
1805     if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1806         if (!value) {
1807             // deleting getter/setter
1808             if ((flags & QScriptValue::PropertyGetter) && (flags & QScriptValue::PropertySetter)) {
1809                 // deleting both: just delete the property
1810                 thisObject->deleteProperty(exec, id);
1811             } else if (flags & QScriptValue::PropertyGetter) {
1812                 // preserve setter, if there is one
1813                 thisObject->deleteProperty(exec, id);
1814                 if (setter && setter.isObject())
1815                     thisObject->defineSetter(exec, id, JSC::asObject(setter));
1816             } else { // flags & QScriptValue::PropertySetter
1817                 // preserve getter, if there is one
1818                 thisObject->deleteProperty(exec, id);
1819                 if (getter && getter.isObject())
1820                     thisObject->defineGetter(exec, id, JSC::asObject(getter));
1821             }
1822         } else {
1823             if (value.isObject()) { // ### should check if it has callData()
1824                 // defining getter/setter
1825                 if (id == exec->propertyNames().underscoreProto) {
1826                     qWarning("QScriptValue::setProperty() failed: "
1827                              "cannot set getter or setter of native property `__proto__'");
1828                 } else {
1829                     if (flags & QScriptValue::PropertyGetter)
1830                         thisObject->defineGetter(exec, id, JSC::asObject(value));
1831                     if (flags & QScriptValue::PropertySetter)
1832                         thisObject->defineSetter(exec, id, JSC::asObject(value));
1833                 }
1834             } else {
1835                 qWarning("QScriptValue::setProperty(): getter/setter must be a function");
1836             }
1837         }
1838     } else {
1839         // setting the value
1840         if (getter && getter.isObject() && !(setter && setter.isObject())) {
1841             qWarning("QScriptValue::setProperty() failed: "
1842                      "property '%s' has a getter but no setter",
1843                      qPrintable(QString(id.ustring())));
1844             return;
1845         }
1846         if (!value) {
1847             // ### check if it's a getter/setter property
1848             thisObject->deleteProperty(exec, id);
1849         } else if (flags != QScriptValue::KeepExistingFlags) {
1850             if (thisObject->hasOwnProperty(exec, id))
1851                 thisObject->deleteProperty(exec, id); // ### hmmm - can't we just update the attributes?
1852             thisObject->putWithAttributes(exec, id, value, propertyFlagsToJSCAttributes(flags));
1853         } else {
1854             JSC::PutPropertySlot slot;
1855             thisObject->put(exec, id, value, slot);
1856         }
1857     }
1858 }
1859
1860 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, quint32 index,
1861                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1862 {
1863     if (!value) {
1864         JSC::asObject(objectValue)->deleteProperty(exec, index);
1865     } else {
1866         if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1867             // fall back to string-based setProperty(), since there is no
1868             // JSC::JSObject::defineGetter(unsigned)
1869             setProperty(exec, objectValue, JSC::Identifier::from(exec, index), value, flags);
1870         } else {
1871             if (flags != QScriptValue::KeepExistingFlags) {
1872                 //                if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
1873                 //                    JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
1874                 unsigned attribs = 0;
1875                 if (flags & QScriptValue::ReadOnly)
1876                     attribs |= JSC::ReadOnly;
1877                 if (flags & QScriptValue::SkipInEnumeration)
1878                     attribs |= JSC::DontEnum;
1879                 if (flags & QScriptValue::Undeletable)
1880                     attribs |= JSC::DontDelete;
1881                 attribs |= flags & QScriptValue::UserRange;
1882                 JSC::asObject(objectValue)->putWithAttributes(exec, index, value, attribs);
1883             } else {
1884                 JSC::asObject(objectValue)->put(exec, index, value);
1885             }
1886         }
1887     }
1888 }
1889
1890 QScriptValue::PropertyFlags QScriptEnginePrivate::propertyFlags(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id,
1891                                                                 const QScriptValue::ResolveFlags &mode)
1892 {
1893     JSC::JSObject *object = JSC::asObject(value);
1894     unsigned attribs = 0;
1895     JSC::PropertyDescriptor descriptor;
1896     if (object->getOwnPropertyDescriptor(exec, id, descriptor))
1897         attribs = descriptor.attributes();
1898     else {
1899         if ((mode & QScriptValue::ResolvePrototype) && object->prototype() && object->prototype().isObject()) {
1900             JSC::JSValue proto = object->prototype();
1901             return propertyFlags(exec, proto, id, mode);
1902         }
1903         return 0;
1904     }
1905     QScriptValue::PropertyFlags result = 0;
1906     if (attribs & JSC::ReadOnly)
1907         result |= QScriptValue::ReadOnly;
1908     if (attribs & JSC::DontEnum)
1909         result |= QScriptValue::SkipInEnumeration;
1910     if (attribs & JSC::DontDelete)
1911         result |= QScriptValue::Undeletable;
1912     //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?)
1913     if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull())
1914         result |= QScriptValue::PropertyGetter;
1915     if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull())
1916         result |= QScriptValue::PropertySetter;
1917 #ifndef QT_NO_QOBJECT
1918     if (attribs & QScript::QObjectMemberAttribute)
1919         result |= QScriptValue::QObjectMember;
1920 #endif
1921     result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange);
1922     return result;
1923 }
1924
1925 QScriptString QScriptEnginePrivate::toStringHandle(const JSC::Identifier &name)
1926 {
1927     QScriptString result;
1928     QScriptStringPrivate *p = new QScriptStringPrivate(this, name, QScriptStringPrivate::HeapAllocated);
1929     QScriptStringPrivate::init(result, p);
1930     registerScriptString(p);
1931     return result;
1932 }
1933
1934 #ifdef QT_NO_QOBJECT
1935
1936 QScriptEngine::QScriptEngine()
1937     : d_ptr(new QScriptEnginePrivate)
1938 {
1939     d_ptr->q_ptr = this;
1940 }
1941
1942 /*! \internal
1943 */
1944 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd)
1945     : d_ptr(&dd)
1946 {
1947     d_ptr->q_ptr = this;
1948 }
1949 #else
1950
1951 /*!
1952     Constructs a QScriptEngine object.
1953
1954     The globalObject() is initialized to have properties as described in
1955     \l{ECMA-262}, Section 15.1.
1956 */
1957 QScriptEngine::QScriptEngine()
1958     : QObject(*new QScriptEnginePrivate, 0)
1959 {
1960 }
1961
1962 /*!
1963     Constructs a QScriptEngine object with the given \a parent.
1964
1965     The globalObject() is initialized to have properties as described in
1966     \l{ECMA-262}, Section 15.1.
1967 */
1968
1969 QScriptEngine::QScriptEngine(QObject *parent)
1970     : QObject(*new QScriptEnginePrivate, parent)
1971 {
1972 }
1973
1974 /*! \internal
1975 */
1976 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent)
1977     : QObject(dd, parent)
1978 {
1979 }
1980 #endif
1981
1982 /*!
1983   Destroys this QScriptEngine.
1984 */
1985 QScriptEngine::~QScriptEngine()
1986 {
1987 #ifdef QT_NO_QOBJECT
1988     delete d_ptr;
1989     d_ptr = 0;
1990 #endif
1991 }
1992
1993 /*!
1994   Returns this engine's Global Object.
1995
1996   By default, the Global Object contains the built-in objects that are
1997   part of \l{ECMA-262}, such as Math, Date and String. Additionally,
1998   you can set properties of the Global Object to make your own
1999   extensions available to all script code. Non-local variables in
2000   script code will be created as properties of the Global Object, as
2001   well as local variables in global code.
2002 */
2003 QScriptValue QScriptEngine::globalObject() const
2004 {
2005     Q_D(const QScriptEngine);
2006     QScript::APIShim shim(const_cast<QScriptEnginePrivate*>(d));
2007     JSC::JSObject *result = d->globalObject();
2008     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(result);
2009 }
2010
2011 /*!
2012   \since 4.5
2013
2014   Sets this engine's Global Object to be the given \a object.
2015   If \a object is not a valid script object, this function does
2016   nothing.
2017
2018   When setting a custom global object, you may want to use
2019   QScriptValueIterator to copy the properties of the standard Global
2020   Object; alternatively, you can set the internal prototype of your
2021   custom object to be the original Global Object.
2022 */
2023 void QScriptEngine::setGlobalObject(const QScriptValue &object)
2024 {
2025     Q_D(QScriptEngine);
2026     if (!object.isObject())
2027         return;
2028     QScript::APIShim shim(d);
2029     JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object));
2030     d->setGlobalObject(jscObject);
2031 }
2032
2033 /*!
2034   Returns a QScriptValue of the primitive type Null.
2035
2036   \sa undefinedValue()
2037 */
2038 QScriptValue QScriptEngine::nullValue()
2039 {
2040     Q_D(QScriptEngine);
2041     return d->scriptValueFromJSCValue(JSC::jsNull());
2042 }
2043
2044 /*!
2045   Returns a QScriptValue of the primitive type Undefined.
2046
2047   \sa nullValue()
2048 */
2049 QScriptValue QScriptEngine::undefinedValue()
2050 {
2051     Q_D(QScriptEngine);
2052     return d->scriptValueFromJSCValue(JSC::jsUndefined());
2053 }
2054
2055 /*!
2056   Creates a constructor function from \a fun, with the given \a length.
2057   The \c{prototype} property of the resulting function is set to be the
2058   given \a prototype. The \c{constructor} property of \a prototype is
2059   set to be the resulting function.
2060
2061   When a function is called as a constructor (e.g. \c{new Foo()}), the
2062   `this' object associated with the function call is the new object
2063   that the function is expected to initialize; the prototype of this
2064   default constructed object will be the function's public
2065   \c{prototype} property. If you always want the function to behave as
2066   a constructor (e.g. \c{Foo()} should also create a new object), or
2067   if you need to create your own object rather than using the default
2068   `this' object, you should make sure that the prototype of your
2069   object is set correctly; either by setting it manually, or, when
2070   wrapping a custom type, by having registered the defaultPrototype()
2071   of that type. Example:
2072
2073   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 9
2074
2075   To wrap a custom type and provide a constructor for it, you'd typically
2076   do something like this:
2077
2078   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 10
2079 */
2080 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun,
2081                                         const QScriptValue &prototype,
2082                                         int length)
2083 {
2084     Q_D(QScriptEngine);
2085     QScript::APIShim shim(d);
2086     JSC::ExecState* exec = d->currentFrame;
2087     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2088     QScriptValue result = d->scriptValueFromJSCValue(function);
2089     result.setProperty(QLatin1String("prototype"), prototype, QScriptValue::Undeletable);
2090     const_cast<QScriptValue&>(prototype)
2091         .setProperty(QLatin1String("constructor"), result,
2092                      QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2093     return result;
2094 }
2095
2096 #ifndef QT_NO_REGEXP
2097
2098 /*!
2099   Creates a QtScript object of class RegExp with the given
2100   \a regexp.
2101
2102   \sa QScriptValue::toRegExp()
2103 */
2104 QScriptValue QScriptEngine::newRegExp(const QRegExp &regexp)
2105 {
2106     Q_D(QScriptEngine);
2107     QScript::APIShim shim(d);
2108     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, regexp));
2109 }
2110
2111 #endif // QT_NO_REGEXP
2112
2113 /*!
2114   Creates a QtScript object holding the given variant \a value.
2115
2116   If a default prototype has been registered with the meta type id of
2117   \a value, then the prototype of the created object will be that
2118   prototype; otherwise, the prototype will be the Object prototype
2119   object.
2120
2121   \sa setDefaultPrototype(), QScriptValue::toVariant(), reportAdditionalMemoryCost()
2122 */
2123 QScriptValue QScriptEngine::newVariant(const QVariant &value)
2124 {
2125     Q_D(QScriptEngine);
2126     QScript::APIShim shim(d);
2127     return d->scriptValueFromJSCValue(d->newVariant(value));
2128 }
2129
2130 /*!
2131   \since 4.4
2132   \overload
2133
2134   Initializes the given Qt Script \a object to hold the given variant
2135   \a value, and returns the \a object.
2136
2137   This function enables you to "promote" a plain Qt Script object
2138   (created by the newObject() function) to a variant, or to replace
2139   the variant contained inside an object previously created by the
2140   newVariant() function.
2141
2142   The prototype() of the \a object will remain unchanged.
2143
2144   If \a object is not an object, this function behaves like the normal
2145   newVariant(), i.e. it creates a new script object and returns it.
2146
2147   This function is useful when you want to provide a script
2148   constructor for a C++ type. If your constructor is invoked in a
2149   \c{new} expression (QScriptContext::isCalledAsConstructor() returns
2150   true), you can pass QScriptContext::thisObject() (the default
2151   constructed script object) to this function to initialize the new
2152   object.
2153
2154   \sa reportAdditionalMemoryCost()
2155 */
2156 QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
2157                                        const QVariant &value)
2158 {
2159     Q_D(QScriptEngine);
2160     QScript::APIShim shim(d);
2161     JSC::JSValue jsObject = d->scriptValueToJSCValue(object);
2162     return d->scriptValueFromJSCValue(d->newVariant(jsObject, value));
2163 }
2164
2165 #ifndef QT_NO_QOBJECT
2166 /*!
2167   Creates a QtScript object that wraps the given QObject \a
2168   object, using the given \a ownership. The given \a options control
2169   various aspects of the interaction with the resulting script object.
2170
2171   Signals and slots, properties and children of \a object are
2172   available as properties of the created QScriptValue. For more
2173   information, see the \l{QtScript} documentation.
2174
2175   If \a object is a null pointer, this function returns nullValue().
2176
2177   If a default prototype has been registered for the \a object's class
2178   (or its superclass, recursively), the prototype of the new script
2179   object will be set to be that default prototype.
2180
2181   If the given \a object is deleted outside of QtScript's control, any
2182   attempt to access the deleted QObject's members through the QtScript
2183   wrapper object (either by script code or C++) will result in a
2184   script exception.
2185
2186   \sa QScriptValue::toQObject(), reportAdditionalMemoryCost()
2187 */
2188 QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership,
2189                                        const QObjectWrapOptions &options)
2190 {
2191     Q_D(QScriptEngine);
2192     QScript::APIShim shim(d);
2193     JSC::JSValue jscQObject = d->newQObject(object, ownership, options);
2194     return d->scriptValueFromJSCValue(jscQObject);
2195 }
2196
2197 /*!
2198   \since 4.4
2199   \overload
2200
2201   Initializes the given \a scriptObject to hold the given \a qtObject,
2202   and returns the \a scriptObject.
2203
2204   This function enables you to "promote" a plain Qt Script object
2205   (created by the newObject() function) to a QObject proxy, or to
2206   replace the QObject contained inside an object previously created by
2207   the newQObject() function.
2208
2209   The prototype() of the \a scriptObject will remain unchanged.
2210
2211   If \a scriptObject is not an object, this function behaves like the
2212   normal newQObject(), i.e. it creates a new script object and returns
2213   it.
2214
2215   This function is useful when you want to provide a script
2216   constructor for a QObject-based class. If your constructor is
2217   invoked in a \c{new} expression
2218   (QScriptContext::isCalledAsConstructor() returns true), you can pass
2219   QScriptContext::thisObject() (the default constructed script object)
2220   to this function to initialize the new object.
2221
2222   \sa reportAdditionalMemoryCost()
2223 */
2224 QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
2225                                        QObject *qtObject,
2226                                        ValueOwnership ownership,
2227                                        const QObjectWrapOptions &options)
2228 {
2229     Q_D(QScriptEngine);
2230     if (!scriptObject.isObject())
2231         return newQObject(qtObject, ownership, options);
2232     QScript::APIShim shim(d);
2233     JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
2234     if (!jscObject->inherits(&QScriptObject::info)) {
2235         qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
2236         return QScriptValue();
2237     }
2238     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
2239     if (!scriptObject.isQObject()) {
2240         jscScriptObject->setDelegate(new QScript::QObjectDelegate(qtObject, ownership, options));
2241     } else {
2242         QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(jscScriptObject->delegate());
2243         delegate->setValue(qtObject);
2244         delegate->setOwnership(ownership);
2245         delegate->setOptions(options);
2246     }
2247     return scriptObject;
2248 }
2249
2250 #endif // QT_NO_QOBJECT
2251
2252 /*!
2253   Creates a QtScript object of class Object.
2254
2255   The prototype of the created object will be the Object
2256   prototype object.
2257
2258   \sa newArray(), QScriptValue::setProperty()
2259 */
2260 QScriptValue QScriptEngine::newObject()
2261 {
2262     Q_D(QScriptEngine);
2263     QScript::APIShim shim(d);
2264     return d->scriptValueFromJSCValue(d->newObject());
2265 }
2266
2267 /*!
2268   \since 4.4
2269   \overload
2270
2271   Creates a QtScript Object of the given class, \a scriptClass.
2272
2273   The prototype of the created object will be the Object
2274   prototype object.
2275
2276   \a data, if specified, is set as the internal data of the
2277   new object (using QScriptValue::setData()).
2278
2279   \sa QScriptValue::scriptClass(), reportAdditionalMemoryCost()
2280 */
2281 QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
2282                                       const QScriptValue &data)
2283 {
2284     Q_D(QScriptEngine);
2285     QScript::APIShim shim(d);
2286     JSC::ExecState* exec = d->currentFrame;
2287     QScriptObject *result = new (exec) QScriptObject(d->scriptObjectStructure);
2288     result->setDelegate(new QScript::ClassObjectDelegate(scriptClass));
2289     QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
2290     scriptObject.setData(data);
2291     QScriptValue proto = scriptClass->prototype();
2292     if (proto.isValid())
2293         scriptObject.setPrototype(proto);
2294     return scriptObject;
2295 }
2296
2297 /*!
2298   \internal
2299 */
2300 QScriptValue QScriptEngine::newActivationObject()
2301 {
2302     qWarning("QScriptEngine::newActivationObject() not implemented");
2303     // ### JSActivation or JSVariableObject?
2304     return QScriptValue();
2305 }
2306
2307 /*!
2308   Creates a QScriptValue that wraps a native (C++) function. \a fun
2309   must be a C++ function with signature QScriptEngine::FunctionSignature.  \a
2310   length is the number of arguments that \a fun expects; this becomes
2311   the \c{length} property of the created QScriptValue.
2312
2313   Note that \a length only gives an indication of the number of
2314   arguments that the function expects; an actual invocation of a
2315   function can include any number of arguments. You can check the
2316   \l{QScriptContext::argumentCount()}{argumentCount()} of the
2317   QScriptContext associated with the invocation to determine the
2318   actual number of arguments passed.
2319
2320   A \c{prototype} property is automatically created for the resulting
2321   function object, to provide for the possibility that the function
2322   will be used as a constructor.
2323
2324   By combining newFunction() and the property flags
2325   QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
2326   can create script object properties that behave like normal
2327   properties in script code, but are in fact accessed through
2328   functions (analogous to how properties work in \l{Qt's Property
2329   System}). Example:
2330
2331   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 11
2332
2333   When the property \c{foo} of the script object is subsequently
2334   accessed in script code, \c{getSetFoo()} will be invoked to handle
2335   the access.  In this particular case, we chose to store the "real"
2336   value of \c{foo} as a property of the accessor function itself; you
2337   are of course free to do whatever you like in this function.
2338
2339   In the above example, a single native function was used to handle
2340   both reads and writes to the property; the argument count is used to
2341   determine if we are handling a read or write. You can also use two
2342   separate functions; just specify the relevant flag
2343   (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
2344   setting the property, e.g.:
2345
2346   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 12
2347
2348   \sa QScriptValue::call()
2349 */
2350 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
2351 {
2352     Q_D(QScriptEngine);
2353     QScript::APIShim shim(d);
2354     JSC::ExecState* exec = d->currentFrame;
2355     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2356     QScriptValue result = d->scriptValueFromJSCValue(function);
2357     QScriptValue proto = newObject();
2358     result.setProperty(QLatin1String("prototype"), proto, QScriptValue::Undeletable);
2359     proto.setProperty(QLatin1String("constructor"), result,
2360                       QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2361     return result;
2362 }
2363
2364 /*!
2365   \internal
2366   \since 4.4
2367 */
2368 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg)
2369 {
2370     Q_D(QScriptEngine);
2371     QScript::APIShim shim(d);
2372     JSC::ExecState* exec = d->currentFrame;
2373     JSC::JSValue function = new (exec)QScript::FunctionWithArgWrapper(exec, /*length=*/0, JSC::Identifier(exec, ""), fun, arg);
2374     QScriptValue result = d->scriptValueFromJSCValue(function);
2375     QScriptValue proto = newObject();
2376     result.setProperty(QLatin1String("prototype"), proto, QScriptValue::Undeletable);
2377     proto.setProperty(QLatin1String("constructor"), result,
2378                       QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2379     return result;
2380 }
2381
2382 /*!
2383   Creates a QtScript object of class Array with the given \a length.
2384
2385   \sa newObject()
2386 */
2387 QScriptValue QScriptEngine::newArray(uint length)
2388 {
2389     Q_D(QScriptEngine);
2390     QScript::APIShim shim(d);
2391     return d->scriptValueFromJSCValue(d->newArray(d->currentFrame, length));
2392 }
2393
2394 /*!
2395   Creates a QtScript object of class RegExp with the given
2396   \a pattern and \a flags.
2397
2398   The legal flags are 'g' (global), 'i' (ignore case), and 'm'
2399   (multiline).
2400 */
2401 QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags)
2402 {
2403     Q_D(QScriptEngine);
2404     QScript::APIShim shim(d);
2405     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, pattern, flags));
2406 }
2407
2408 /*!
2409   Creates a QtScript object of class Date with the given
2410   \a value (the number of milliseconds since 01 January 1970,
2411   UTC).
2412 */
2413 QScriptValue QScriptEngine::newDate(qsreal value)
2414 {
2415     Q_D(QScriptEngine);
2416     QScript::APIShim shim(d);
2417     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2418 }
2419
2420 /*!
2421   Creates a QtScript object of class Date from the given \a value.
2422
2423   \sa QScriptValue::toDateTime()
2424 */
2425 QScriptValue QScriptEngine::newDate(const QDateTime &value)
2426 {
2427     Q_D(QScriptEngine);
2428     QScript::APIShim shim(d);
2429     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2430 }
2431
2432 #ifndef QT_NO_QOBJECT
2433 /*!
2434   Creates a QtScript object that represents a QObject class, using the
2435   the given \a metaObject and constructor \a ctor.
2436
2437   Enums of \a metaObject (declared with Q_ENUMS) are available as
2438   properties of the created QScriptValue. When the class is called as
2439   a function, \a ctor will be called to create a new instance of the
2440   class.
2441
2442   Example:
2443
2444   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 27
2445
2446   \sa newQObject(), scriptValueFromQMetaObject()
2447 */
2448 QScriptValue QScriptEngine::newQMetaObject(
2449     const QMetaObject *metaObject, const QScriptValue &ctor)
2450 {
2451     Q_D(QScriptEngine);
2452     QScript::APIShim shim(d);
2453     JSC::JSValue jscCtor = d->scriptValueToJSCValue(ctor);
2454     JSC::JSValue jscQMetaObject = d->newQMetaObject(metaObject, jscCtor);
2455     return d->scriptValueFromJSCValue(jscQMetaObject);
2456 }
2457
2458 /*!
2459   \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject()
2460
2461   Creates a QScriptValue that represents the Qt class \c{T}.
2462
2463   This function is used in combination with one of the
2464   Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example:
2465
2466   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 13
2467
2468   \warning This function is not available with MSVC 6. Use
2469   qScriptValueFromQMetaObject() instead if you need to support that version
2470   of the compiler.
2471
2472   \sa QScriptEngine::newQMetaObject()
2473 */
2474
2475 /*!
2476   \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine)
2477   \since 4.3
2478   \relates QScriptEngine
2479
2480   Uses \a engine to create a QScriptValue that represents the Qt class
2481   \c{T}.
2482
2483   This function is equivalent to
2484   QScriptEngine::scriptValueFromQMetaObject(). It is provided as a
2485   work-around for MSVC 6, which doesn't support member template
2486   functions.
2487
2488   \sa QScriptEngine::newQMetaObject()
2489 */
2490 #endif // QT_NO_QOBJECT
2491
2492 /*!
2493   \obsolete
2494
2495   Returns true if \a program can be evaluated; i.e. the code is
2496   sufficient to determine whether it appears to be a syntactically
2497   correct program, or contains a syntax error.
2498
2499   This function returns false if \a program is incomplete; i.e. the
2500   input is syntactically correct up to the point where the input is
2501   terminated.
2502
2503   Note that this function only does a static check of \a program;
2504   e.g. it does not check whether references to variables are
2505   valid, and so on.
2506
2507   A typical usage of canEvaluate() is to implement an interactive
2508   interpreter for QtScript. The user is repeatedly queried for
2509   individual lines of code; the lines are concatened internally, and
2510   only when canEvaluate() returns true for the resulting program is it
2511   passed to evaluate().
2512
2513   The following are some examples to illustrate the behavior of
2514   canEvaluate(). (Note that all example inputs are assumed to have an
2515   explicit newline as their last character, since otherwise the
2516   QtScript parser would automatically insert a semi-colon character at
2517   the end of the input, and this could cause canEvaluate() to produce
2518   different results.)
2519
2520   Given the input
2521   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 14
2522   canEvaluate() will return true, since the program appears to be complete.
2523
2524   Given the input
2525   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 15
2526   canEvaluate() will return false, since the if-statement is not complete,
2527   but is syntactically correct so far.
2528
2529   Given the input
2530   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 16
2531   canEvaluate() will return true, but evaluate() will throw a
2532   SyntaxError given the same input.
2533
2534   Given the input
2535   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 17
2536   canEvaluate() will return true, even though the code is clearly not
2537   syntactically valid QtScript code. evaluate() will throw a
2538   SyntaxError when this code is evaluated.
2539
2540   Given the input
2541   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 18
2542   canEvaluate() will return true, but evaluate() will throw a
2543   ReferenceError if \c{foo} is not defined in the script
2544   environment.
2545
2546   \sa evaluate(), checkSyntax()
2547 */
2548 bool QScriptEngine::canEvaluate(const QString &program) const
2549 {
2550     return QScriptEnginePrivate::canEvaluate(program);
2551 }
2552
2553
2554 bool QScriptEnginePrivate::canEvaluate(const QString &program)
2555 {
2556     QScript::SyntaxChecker checker;
2557     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2558     return (result.state != QScript::SyntaxChecker::Intermediate);
2559 }
2560
2561 /*!
2562   \since 4.5
2563
2564   Checks the syntax of the given \a program. Returns a
2565   QScriptSyntaxCheckResult object that contains the result of the check.
2566 */
2567 QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program)
2568 {
2569     return QScriptEnginePrivate::checkSyntax(program);
2570 }
2571
2572 QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2573 {
2574     QScript::SyntaxChecker checker;
2575     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2576     QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2577     switch (result.state) {
2578     case QScript::SyntaxChecker::Error:
2579         p->state = QScriptSyntaxCheckResult::Error;
2580         break;
2581     case QScript::SyntaxChecker::Intermediate:
2582         p->state = QScriptSyntaxCheckResult::Intermediate;
2583         break;
2584     case QScript::SyntaxChecker::Valid:
2585         p->state = QScriptSyntaxCheckResult::Valid;
2586         break;
2587     }
2588     p->errorLineNumber = result.errorLineNumber;
2589     p->errorColumnNumber = result.errorColumnNumber;
2590     p->errorMessage = result.errorMessage;
2591     return QScriptSyntaxCheckResult(p);
2592 }
2593
2594
2595
2596 /*!
2597   Evaluates \a program, using \a lineNumber as the base line number,
2598   and returns the result of the evaluation.
2599
2600   The script code will be evaluated in the current context.
2601
2602   The evaluation of \a program can cause an exception in the
2603   engine; in this case the return value will be the exception
2604   that was thrown (typically an \c{Error} object). You can call
2605   hasUncaughtException() to determine if an exception occurred in
2606   the last call to evaluate().
2607
2608   \a lineNumber is used to specify a starting line number for \a
2609   program; line number information reported by the engine that pertain
2610   to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
2611   based on this argument. For example, if \a program consists of two
2612   lines of code, and the statement on the second line causes a script
2613   exception, uncaughtExceptionLineNumber() would return the given \a
2614   lineNumber plus one. When no starting line number is specified, line
2615   numbers will be 1-based.
2616
2617   \a fileName is used for error reporting. For example in error objects
2618   the file name is accessible through the "fileName" property if it's
2619   provided with this function.
2620
2621   \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
2622 */
2623
2624 QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
2625 {
2626     Q_D(QScriptEngine);
2627     QScript::APIShim shim(d);
2628     WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
2629             = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
2630     intptr_t sourceId = provider->asID();
2631     JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
2632
2633     JSC::ExecState* exec = d->currentFrame;
2634     WTF::RefPtr<JSC::EvalExecutable> executable = JSC::EvalExecutable::create(exec, source);
2635     bool compile = true;
2636     return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, executable.get(), compile));
2637 }
2638
2639 /*!
2640   \since 4.7
2641
2642   Evaluates the given \a program and returns the result of the
2643   evaluation.
2644 */
2645 QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
2646 {
2647     Q_D(QScriptEngine);
2648     QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
2649     if (!program_d)
2650         return QScriptValue();
2651
2652     QScript::APIShim shim(d);
2653     JSC::ExecState* exec = d->currentFrame;
2654     JSC::EvalExecutable *executable = program_d->executable(exec, d);
2655     bool compile = !program_d->isCompiled;
2656     JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
2657                                             executable, compile);
2658     if (compile)
2659         program_d->isCompiled = true;
2660     return d->scriptValueFromJSCValue(result);
2661 }
2662
2663 /*!
2664   Returns the current context.
2665
2666   The current context is typically accessed to retrieve the arguments
2667   and `this' object in native functions; for convenience, it is
2668   available as the first argument in QScriptEngine::FunctionSignature.
2669 */
2670 QScriptContext *QScriptEngine::currentContext() const
2671 {
2672     Q_D(const QScriptEngine);
2673     return const_cast<QScriptEnginePrivate*>(d)->contextForFrame(d->currentFrame);
2674 }
2675
2676 /*!
2677   Enters a new execution context and returns the associated
2678   QScriptContext object.
2679
2680   Once you are done with the context, you should call popContext() to
2681   restore the old context.
2682
2683   By default, the `this' object of the new context is the Global Object.
2684   The context's \l{QScriptContext::callee()}{callee}() will be invalid.
2685
2686   This function is useful when you want to evaluate script code
2687   as if it were the body of a function. You can use the context's
2688   \l{QScriptContext::activationObject()}{activationObject}() to initialize
2689   local variables that will be available to scripts. Example:
2690
2691   \snippet doc/src/snippets/code/src_script_qscriptengine.cpp 19
2692
2693   In the above example, the new variable "tmp" defined in the script
2694   will be local to the context; in other words, the script doesn't
2695   have any effect on the global environment.
2696
2697   Returns 0 in case of stack overflow
2698
2699   \sa popContext()
2700 */
2701 QScriptContext *QScriptEngine::pushContext()
2702 {
2703     Q_D(QScriptEngine);
2704     QScript::APIShim shim(d);
2705
2706     JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
2707                                               JSC::ArgList(), /*callee = */0);
2708
2709     if (agent())
2710         agent()->contextPush();
2711
2712     return d->contextForFrame(newFrame);
2713 }
2714
2715 /*! \internal
2716    push a context for a native function.
2717    JSC native function doesn't have different stackframe or context. so we need to create one.
2718
2719    use popContext right after to go back to the previous context the context if no stack overflow has hapenned
2720
2721    exec is the current top frame.
2722
2723    return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
2724 */
2725 JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
2726                                                   const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor,
2727                                                   bool clearScopeChain)
2728 {
2729     JSC::JSValue thisObject = _thisObject;
2730     if (calledAsConstructor) {
2731         //JSC doesn't create default created object for native functions. so we do it
2732         JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
2733         JSC::Structure *structure = prototype.isObject() ? JSC::asObject(prototype)->inheritorID()
2734                                                          : originalGlobalObject()->emptyObjectStructure();
2735         thisObject = new (exec) QScriptObject(structure);
2736     }
2737
2738     int flags = NativeContext;
2739     if (calledAsConstructor)
2740         flags |= CalledAsConstructorContext;
2741
2742     //build a frame
2743     JSC::CallFrame *newCallFrame = exec;
2744     if (callee == 0 //called from  public QScriptEngine::pushContext
2745         || exec->returnPC() == 0 || (contextFlags(exec) & NativeContext) //called from native-native call
2746         || (exec->codeBlock() && exec->callee() != callee)) { //the interpreter did not build a frame for us.
2747         //We need to check if the Interpreter might have already created a frame for function called from JS.
2748         JSC::Interpreter *interp = exec->interpreter();
2749         JSC::Register *oldEnd = interp->registerFile().end();
2750         int argc = args.size() + 1; //add "this"
2751         JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize;
2752         if (!interp->registerFile().grow(newEnd))
2753             return 0; //### Stack overflow
2754         newCallFrame = JSC::CallFrame::create(oldEnd);
2755         newCallFrame[0] = thisObject;
2756         int dst = 0;
2757         JSC::ArgList::const_iterator it;
2758         for (it = args.begin(); it != args.end(); ++it)
2759             newCallFrame[++dst] = *it;
2760         newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
2761
2762         if (!clearScopeChain) {
2763             newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2764         } else {
2765             newCallFrame->init(0, /*vPC=*/0, globalExec()->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2766         }
2767     } else {
2768         setContextFlags(newCallFrame, flags);
2769 #if ENABLE(JIT)
2770         exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
2771 #endif
2772         if (calledAsConstructor) {
2773             //update the new created this
2774             JSC::Register* thisRegister = thisRegisterForFrame(newCallFrame);
2775             *thisRegister = thisObject;
2776         }
2777     }
2778     currentFrame = newCallFrame;
2779     return newCallFrame;
2780 }
2781
2782
2783 /*!
2784   Pops the current execution context and restores the previous one.
2785   This function must be used in conjunction with pushContext().
2786
2787   \sa pushContext()
2788 */
2789 void QScriptEngine::popContext()
2790 {
2791     if (agent())
2792         agent()->contextPop();
2793     Q_D(QScriptEngine);
2794     QScript::APIShim shim(d);
2795     if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0
2796         || !currentContext()->parentContext()) {
2797         qWarning("QScriptEngine::popContext() doesn't match with pushContext()");
2798         return;
2799     }
2800
2801     d->popContext();
2802 }
2803
2804 /*! \internal
2805     counter part of QScriptEnginePrivate::pushContext
2806  */
2807 void QScriptEnginePrivate::popContext()
2808 {
2809     uint flags = contextFlags(currentFrame);
2810     bool hasScope = flags & HasScopeContext;
2811     if (flags & ShouldRestoreCallFrame) { //normal case
2812         JSC::RegisterFile &registerFile = currentFrame->interpreter()->registerFile();
2813         JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount();
2814         if (hasScope)
2815             currentFrame->scopeChain()->pop()->deref();
2816         registerFile.shrink(newEnd);
2817     } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it.
2818         currentFrame->setScopeChain(currentFrame->scopeChain()->pop());
2819         currentFrame->scopeChain()->deref();
2820     }
2821     currentFrame = currentFrame->callerFrame();
2822 }
2823
2824 /*!
2825   Returns true if the last script evaluation resulted in an uncaught
2826   exception; otherwise returns false.
2827
2828   The exception state is cleared when evaluate() is called.
2829
2830   \sa uncaughtException(), uncaughtExceptionLineNumber()
2831 */
2832 bool QScriptEngine::hasUncaughtException() const
2833 {
2834     Q_D(const QScriptEngine);
2835     JSC::ExecState* exec = d->globalExec();
2836     return exec->hadException() || d->currentException().isValid();
2837 }
2838
2839 /*!
2840   Returns the current uncaught exception, or an invalid QScriptValue
2841   if there is no uncaught exception.
2842
2843   The exception value is typically an \c{Error} object; in that case,
2844   you can call toString() on the return value to obtain an error
2845   message.
2846
2847   \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
2848 */
2849 QScriptValue QScriptEngine::uncaughtException() const
2850 {
2851     Q_D(const QScriptEngine);
2852     QScriptValue result;
2853     JSC::ExecState* exec = d->globalExec();
2854     if (exec->hadException())
2855         result = const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(exec->exception());
2856     else
2857         result = d->currentException();
2858     return result;
2859 }
2860
2861 /*!
2862   Returns the line number where the last uncaught exception occurred.
2863
2864   Line numbers are 1-based, unless a different base was specified as
2865   the second argument to evaluate().
2866
2867   \sa hasUncaughtException()
2868 */
2869 int QScriptEngine::uncaughtExceptionLineNumber() const
2870 {
2871     if (!hasUncaughtException())
2872         return -1;
2873     return uncaughtException().property(QLatin1String("lineNumber")).toInt32();
2874 }
2875
2876 /*!
2877   Returns a human-readable backtrace of the last uncaught exception.
2878
2879   It is in the form \c{<function-name>()@<file-name>:<line-number>}.
2880
2881   \sa uncaughtException()
2882 */
2883 QStringList QScriptEngine::uncaughtExceptionBacktrace() const
2884 {
2885     if (!hasUncaughtException())
2886         return QStringList();
2887 // ### currently no way to get a full backtrace from JSC without installing a
2888 // debugger that reimplements exception() and store the backtrace there.
2889     QScriptValue value = uncaughtException();
2890     if (!value.isError())
2891         return QStringList();
2892     QStringList result;
2893     result.append(QString::fromLatin1("<anonymous>()@%0:%1")
2894                   .arg(value.property(QLatin1String("fileName")).toString())
2895                   .arg(value.property(QLatin1String("lineNumber")).toInt32()));
2896     return result;
2897 }
2898
2899 /*!
2900   \since 4.4
2901
2902   Clears any uncaught exceptions in this engine.
2903
2904   \sa hasUncaughtException()
2905 */
2906 void QScriptEngine::clearExceptions()
2907 {
2908     Q_D(QScriptEngine);
2909     JSC::ExecState* exec = d->currentFrame;
2910     exec->clearException();
2911     d->clearCurrentException();
2912 }
2913
2914 /*!
2915   Returns the default prototype associated with the given \a metaTypeId,
2916   or an invalid QScriptValue if no default prototype has been set.
2917
2918   \sa setDefaultPrototype()
2919 */
2920 QScriptValue QScriptEngine::defaultPrototype(int metaTypeId) const
2921 {
2922     Q_D(const QScriptEngine);
2923     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(d->defaultPrototype(metaTypeId));
2924 }
2925
2926 /*!
2927   Sets the default prototype of the C++ type identified by the given
2928   \a metaTypeId to \a prototype.
2929
2930   The default prototype provides a script interface for values of
2931   type \a metaTypeId when a value of that type is accessed from script
2932   code.  Whenever the script engine (implicitly or explicitly) creates
2933   a QScriptValue from a value of type \a metaTypeId, the default
2934   prototype will be set as the QScriptValue's prototype.
2935
2936   The \a prototype object itself may be constructed using one of two
2937   principal techniques; the simplest is to subclass QScriptable, which
2938   enables you to define the scripting API of the type through QObject
2939   properties and slots.  Another possibility is to create a script
2940   object by calling newObject(), and populate the object with the
2941   desired properties (e.g. native functions wrapped with
2942   newFunction()).
2943
2944   \sa defaultPrototype(), qScriptRegisterMetaType(), QScriptable, {Default Prototypes Example}
2945 */
2946 void QScriptEngine::setDefaultPrototype(int metaTypeId, const QScriptValue &prototype)
2947 {
2948     Q_D(QScriptEngine);
2949     d->setDefaultPrototype(metaTypeId, d->scriptValueToJSCValue(prototype));
2950 }
2951
2952 /*!
2953   \typedef QScriptEngine::FunctionSignature
2954   \relates QScriptEngine
2955
2956   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
2957
2958   A function with such a signature can be passed to
2959   QScriptEngine::newFunction() to wrap the function.
2960 */
2961
2962 /*!
2963   \typedef QScriptEngine::FunctionWithArgSignature
2964   \relates QScriptEngine
2965
2966   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
2967
2968   A function with such a signature can be passed to
2969   QScriptEngine::newFunction() to wrap the function.
2970 */
2971
2972 /*!
2973     \typedef QScriptEngine::MarshalFunction
2974     \internal
2975 */
2976
2977 /*!
2978     \typedef QScriptEngine::DemarshalFunction
2979     \internal
2980 */
2981
2982 /*!
2983     \internal
2984 */
2985 QScriptValue QScriptEngine::create(int type, const void *ptr)
2986 {
2987     Q_D(QScriptEngine);
2988     QScript::APIShim shim(d);
2989     return d->scriptValueFromJSCValue(d->create(d->currentFrame, type, ptr));
2990 }
2991
2992 JSC::JSValue QScriptEnginePrivate::create(JSC::ExecState *exec, int type, const void *ptr)
2993 {
2994     Q_ASSERT(ptr != 0);
2995     JSC::JSValue result;
2996     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
2997     QScriptTypeInfo *info = eng ? eng->m_typeInfos.value(type) : 0;
2998     if (info && info->marshal) {
2999         result = eng->scriptValueToJSCValue(info->marshal(eng->q_func(), ptr));
3000     } else {
3001         // check if it's one of the types we know
3002         switch (QMetaType::Type(type)) {
3003         case QMetaType::Void:
3004             return JSC::jsUndefined();
3005         case QMetaType::Bool:
3006             return JSC::jsBoolean(*reinterpret_cast<const bool*>(ptr));
3007         case QMetaType::Int:
3008             return JSC::jsNumber(exec, *reinterpret_cast<const int*>(ptr));
3009         case QMetaType::UInt:
3010             return JSC::jsNumber(exec, *reinterpret_cast<const uint*>(ptr));
3011         case QMetaType::LongLong:
3012             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
3013         case QMetaType::ULongLong:
3014 #if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
3015 #pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
3016             return JSC::jsNumber(exec, qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
3017 #elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
3018             return JSC::jsNumber(exec, qsreal((qlonglong)*reinterpret_cast<const qulonglong*>(ptr)));
3019 #else
3020             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
3021 #endif
3022         case QMetaType::Double:
3023             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const double*>(ptr)));
3024         case QMetaType::QString:
3025             return JSC::jsString(exec, *reinterpret_cast<const QString*>(ptr));
3026         case QMetaType::Float:
3027             return JSC::jsNumber(exec, *reinterpret_cast<const float*>(ptr));
3028         case QMetaType::Short:
3029             return JSC::jsNumber(exec, *reinterpret_cast<const short*>(ptr));
3030         case QMetaType::UShort:
3031             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned short*>(ptr));
3032         case QMetaType::Char:
3033             return JSC::jsNumber(exec, *reinterpret_cast<const char*>(ptr));
3034         case QMetaType::UChar:
3035             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned char*>(ptr));
3036         case QMetaType::QChar:
3037             return JSC::jsNumber(exec, (*reinterpret_cast<const QChar*>(ptr)).unicode());
3038         case QMetaType::QStringList:
3039             result = arrayFromStringList(exec, *reinterpret_cast<const QStringList *>(ptr));
3040             break;
3041         case QMetaType::QVariantList:
3042             result = arrayFromVariantList(exec, *reinterpret_cast<const QVariantList *>(ptr));
3043             break;
3044         case QMetaType::QVariantMap:
3045             result = objectFromVariantMap(exec, *reinterpret_cast<const QVariantMap *>(ptr));
3046             break;
3047         case QMetaType::QDateTime:
3048             result = newDate(exec, *reinterpret_cast<const QDateTime *>(ptr));
3049             break;
3050         case QMetaType::QDate:
3051             result = newDate(exec, QDateTime(*reinterpret_cast<const QDate *>(ptr)));
3052             break;
3053 #ifndef QT_NO_REGEXP
3054         case QMetaType::QRegExp:
3055             result = newRegExp(exec, *reinterpret_cast<const QRegExp *>(ptr));
3056             break;
3057 #endif
3058 #ifndef QT_NO_QOBJECT
3059         case QMetaType::QObjectStar:
3060         case QMetaType::QWidgetStar:
3061             result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr));
3062             break;
3063 #endif
3064         case QMetaType::QVariant:
3065             result = jscValueFromVariant(exec, *reinterpret_cast<const QVariant*>(ptr));
3066             break;
3067         default:
3068             if (type == qMetaTypeId<QScriptValue>()) {
3069                 result = eng->scriptValueToJSCValue(*reinterpret_cast<const QScriptValue*>(ptr));
3070                 if (!result)
3071                     return JSC::jsUndefined();
3072             }
3073
3074 #ifndef QT_NO_QOBJECT
3075             // lazy registration of some common list types
3076             else if (type == qMetaTypeId<QObjectList>()) {
3077                 qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3078                 return create(exec, type, ptr);
3079             }
3080 #endif
3081             else if (type == qMetaTypeId<QList<int> >()) {
3082                 qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3083                 return create(exec, type, ptr);
3084             }
3085
3086             else {
3087                 QByteArray typeName = QMetaType::typeName(type);
3088                 if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
3089                     return JSC::jsNull();
3090                 else
3091                     result = eng->newVariant(QVariant(type, ptr));
3092             }
3093         }
3094     }
3095     if (result && result.isObject() && info && info->prototype
3096         && JSC::JSValue::strictEqual(exec, JSC::asObject(result)->prototype(), eng->originalGlobalObject()->objectPrototype())) {
3097         JSC::asObject(result)->setPrototype(info->prototype);
3098     }
3099     return result;
3100 }
3101
3102 bool QScriptEnginePrivate::convertValue(JSC::ExecState *exec, JSC::JSValue value,
3103                                         int type, void *ptr)
3104 {
3105     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
3106     if (eng) {
3107         QScriptTypeInfo *info = eng->m_typeInfos.value(type);
3108         if (info && info->demarshal) {
3109             info->demarshal(eng->scriptValueFromJSCValue(value), ptr);
3110             return true;
3111         }
3112     }
3113
3114     // check if it's one of the types we know
3115     switch (QMetaType::Type(type)) {
3116     case QMetaType::Bool:
3117         *reinterpret_cast<bool*>(ptr) = toBool(exec, value);
3118         return true;
3119     case QMetaType::Int:
3120         *reinterpret_cast<int*>(ptr) = toInt32(exec, value);
3121         return true;
3122     case QMetaType::UInt:
3123         *reinterpret_cast<uint*>(ptr) = toUInt32(exec, value);
3124         return true;
3125     case QMetaType::LongLong:
3126         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(toInteger(exec, value));
3127         return true;
3128     case QMetaType::ULongLong:
3129         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(toInteger(exec, value));
3130         return true;
3131     case QMetaType::Double:
3132         *reinterpret_cast<double*>(ptr) = toNumber(exec, value);
3133         return true;
3134     case QMetaType::QString:
3135         if (value.isUndefined() || value.isNull())
3136             *reinterpret_cast<QString*>(ptr) = QString();
3137         else
3138             *reinterpret_cast<QString*>(ptr) = toString(exec, value);
3139         return true;
3140     case QMetaType::Float:
3141         *reinterpret_cast<float*>(ptr) = toNumber(exec, value);
3142         return true;
3143     case QMetaType::Short:
3144         *reinterpret_cast<short*>(ptr) = short(toInt32(exec, value));
3145         return true;
3146     case QMetaType::UShort:
3147         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(toNumber(exec, value));
3148         return true;
3149     case QMetaType::Char:
3150         *reinterpret_cast<char*>(ptr) = char(toInt32(exec, value));
3151         return true;
3152     case QMetaType::UChar:
3153         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(toInt32(exec, value));
3154         return true;
3155     case QMetaType::QChar:
3156         if (value.isString()) {
3157             QString str = toString(exec, value);
3158             *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
3159         } else {
3160             *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(toNumber(exec, value)));
3161         }
3162         return true;
3163     case QMetaType::QDateTime:
3164         if (isDate(value)) {
3165             *reinterpret_cast<QDateTime *>(ptr) = toDateTime(exec, value);
3166             return true;
3167         } break;
3168     case QMetaType::QDate:
3169         if (isDate(value)) {
3170             *reinterpret_cast<QDate *>(ptr) = toDateTime(exec, value).date();
3171             return true;
3172         } break;
3173 #ifndef QT_NO_REGEXP
3174     case QMetaType::QRegExp:
3175         if (isRegExp(value)) {
3176             *reinterpret_cast<QRegExp *>(ptr) = toRegExp(exec, value);
3177             return true;
3178         } break;
3179 #endif
3180 #ifndef QT_NO_QOBJECT
3181     case QMetaType::QObjectStar:
3182         if (isQObject(value) || value.isNull()) {
3183             *reinterpret_cast<QObject* *>(ptr) = toQObject(exec, value);
3184             return true;
3185         } break;
3186     case QMetaType::QWidgetStar:
3187         if (isQObject(value) || value.isNull()) {
3188             QObject *qo = toQObject(exec, value);
3189             if (!qo || qo->isWidgetType()) {
3190                 *reinterpret_cast<QWidget* *>(ptr) = reinterpret_cast<QWidget*>(qo);
3191                 return true;
3192             }
3193         } break;
3194 #endif
3195     case QMetaType::QStringList:
3196         if (isArray(value)) {
3197             *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(exec, value);
3198             return true;
3199         } break;
3200     case QMetaType::QVariantList:
3201         if (isArray(value)) {
3202             *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, JSC::asArray(value));
3203             return true;
3204         } break;
3205     case QMetaType::QVariantMap:
3206         if (isObject(value)) {
3207             *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, JSC::asObject(value));
3208             return true;
3209         } break;
3210     case QMetaType::QVariant:
3211         *reinterpret_cast<QVariant*>(ptr) = toVariant(exec, value);
3212         return true;
3213     default:
3214     ;
3215     }
3216
3217     QByteArray name = QMetaType::typeName(type);
3218 #ifndef QT_NO_QOBJECT
3219     if (convertToNativeQObject(exec, value, name, reinterpret_cast<void* *>(ptr)))
3220         return true;
3221 #endif
3222     if (isVariant(value) && name.endsWith('*')) {
3223         int valueType = QMetaType::type(name.left(name.size()-1));
3224         QVariant &var = variantValue(value);
3225         if (valueType == var.userType()) {
3226             *reinterpret_cast<void* *>(ptr) = var.data();
3227             return true;
3228         } else {
3229             // look in the prototype chain
3230             JSC::JSValue proto = JSC::asObject(value)->prototype();
3231             while (proto.isObject()) {
3232                 bool canCast = false;
3233                 if (isVariant(proto)) {
3234                     canCast = (type == variantValue(proto).userType())
3235                               || (valueType && (valueType == variantValue(proto).userType()));
3236                 }
3237 #ifndef QT_NO_QOBJECT
3238                 else if (isQObject(proto)) {
3239                     QByteArray className = name.left(name.size()-1);
3240                     if (QObject *qobject = toQObject(exec, proto))
3241                         canCast = qobject->qt_metacast(className) != 0;
3242                 }
3243 #endif
3244                 if (canCast) {
3245                     QByteArray varTypeName = QMetaType::typeName(var.userType());
3246                     if (varTypeName.endsWith('*'))
3247                         *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
3248                     else
3249                         *reinterpret_cast<void* *>(ptr) = var.data();
3250                     return true;
3251                 }
3252                 proto = JSC::asObject(proto)->prototype();
3253             }
3254         }
3255     } else if (value.isNull() && name.endsWith('*')) {
3256         *reinterpret_cast<void* *>(ptr) = 0;
3257         return true;
3258     } else if (type == qMetaTypeId<QScriptValue>()) {
3259         if (!eng)
3260             return false;
3261         *reinterpret_cast<QScriptValue*>(ptr) = eng->scriptValueFromJSCValue(value);
3262         return true;
3263     }
3264
3265     // lazy registration of some common list types
3266 #ifndef QT_NO_QOBJECT
3267     else if (type == qMetaTypeId<QObjectList>()) {
3268         if (!eng)
3269             return false;
3270         qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3271         return convertValue(exec, value, type, ptr);
3272     }
3273 #endif
3274     else if (type == qMetaTypeId<QList<int> >()) {
3275         if (!eng)
3276             return false;
3277         qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3278         return convertValue(exec, value, type, ptr);
3279     }
3280
3281 #if 0
3282     if (!name.isEmpty()) {
3283         qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
3284                  name.constData());
3285     }
3286 #endif
3287     return false;
3288 }
3289
3290 bool QScriptEnginePrivate::convertNumber(qsreal value, int type, void *ptr)
3291 {
3292     switch (QMetaType::Type(type)) {
3293     case QMetaType::Bool:
3294         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3295         return true;
3296     case QMetaType::Int:
3297         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3298         return true;
3299     case QMetaType::UInt:
3300         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3301         return true;
3302     case QMetaType::LongLong:
3303         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3304         return true;
3305     case QMetaType::ULongLong:
3306         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3307         return true;
3308     case QMetaType::Double:
3309         *reinterpret_cast<double*>(ptr) = value;
3310         return true;
3311     case QMetaType::QString:
3312         *reinterpret_cast<QString*>(ptr) = QScript::ToString(value);
3313         return true;
3314     case QMetaType::Float:
3315         *reinterpret_cast<float*>(ptr) = value;
3316         return true;
3317     case QMetaType::Short:
3318         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3319         return true;
3320     case QMetaType::UShort:
3321         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3322         return true;
3323     case QMetaType::Char:
3324         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3325         return true;
3326     case QMetaType::UChar:
3327         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3328         return true;
3329     case QMetaType::QChar:
3330         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3331         return true;
3332     default:
3333         break;
3334     }
3335     return false;
3336 }
3337
3338 bool QScriptEnginePrivate::convertString(const QString &value, int type, void *ptr)
3339 {
3340     switch (QMetaType::Type(type)) {
3341     case QMetaType::Bool:
3342         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3343         return true;
3344     case QMetaType::Int:
3345         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3346         return true;
3347     case QMetaType::UInt:
3348         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3349         return true;
3350     case QMetaType::LongLong:
3351         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3352         return true;
3353     case QMetaType::ULongLong:
3354         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3355         return true;
3356     case QMetaType::Double:
3357         *reinterpret_cast<double*>(ptr) = QScript::ToNumber(value);
3358         return true;
3359     case QMetaType::QString:
3360         *reinterpret_cast<QString*>(ptr) = value;
3361         return true;
3362     case QMetaType::Float:
3363         *reinterpret_cast<float*>(ptr) = QScript::ToNumber(value);
3364         return true;
3365     case QMetaType::Short:
3366         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3367         return true;
3368     case QMetaType::UShort:
3369         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3370         return true;
3371     case QMetaType::Char:
3372         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3373         return true;
3374     case QMetaType::UChar:
3375         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3376         return true;
3377     case QMetaType::QChar:
3378         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3379         return true;
3380     default:
3381         break;
3382     }
3383     return false;
3384 }
3385
3386 bool QScriptEnginePrivate::hasDemarshalFunction(int type) const
3387 {
3388     QScriptTypeInfo *info = m_typeInfos.value(type);
3389     return info && (info->demarshal != 0);
3390 }
3391
3392 JSC::UString QScriptEnginePrivate::translationContextFromUrl(const JSC::UString &url)
3393 {
3394     if (url != cachedTranslationUrl) {
3395         cachedTranslationContext = QFileInfo(url).baseName();
3396         cachedTranslationUrl = url;
3397     }
3398     return cachedTranslationContext;
3399 }
3400
3401 /*!
3402     \internal
3403 */
3404 bool QScriptEngine::convert(const QScriptValue &value, int type, void *ptr)
3405 {
3406     Q_D(QScriptEngine);
3407     QScript::APIShim shim(d);
3408     return QScriptEnginePrivate::convertValue(d->currentFrame, d->scriptValueToJSCValue(value), type, ptr);
3409 }
3410
3411 /*!
3412     \internal
3413 */
3414 bool QScriptEngine::convertV2(const QScriptValue &value, int type, void *ptr)
3415 {
3416     QScriptValuePrivate *vp = QScriptValuePrivate::get(value);
3417     if (vp) {
3418         switch (vp->type) {
3419         case QScriptValuePrivate::JavaScriptCore: {
3420             if (vp->engine) {
3421                 QScript::APIShim shim(vp->engine);
3422                 return QScriptEnginePrivate::convertValue(vp->engine->currentFrame, vp->jscValue, type, ptr);
3423             } else {
3424                 return QScriptEnginePrivate::convertValue(0, vp->jscValue, type, ptr);
3425             }
3426         }
3427         case QScriptValuePrivate::Number:
3428             return QScriptEnginePrivate::convertNumber(vp->numberValue, type, ptr);
3429         case QScriptValuePrivate::String:
3430             return QScriptEnginePrivate::convertString(vp->stringValue, type, ptr);
3431         }
3432     }
3433     return false;
3434 }
3435
3436 /*!
3437     \internal
3438 */
3439 void QScriptEngine::registerCustomType(int type, MarshalFunction mf,
3440                                        DemarshalFunction df,
3441                                        const QScriptValue &prototype)
3442 {
3443     Q_D(QScriptEngine);
3444     QScript::APIShim shim(d);
3445     QScriptTypeInfo *info = d->m_typeInfos.value(type);
3446     if (!info) {
3447         info = new QScriptTypeInfo();
3448         d->m_typeInfos.insert(type, info);
3449     }
3450     info->marshal = mf;
3451     info->demarshal = df;
3452     info->prototype = d->scriptValueToJSCValue(prototype);
3453 }
3454
3455 /*!
3456   \since 4.5
3457
3458   Installs translator functions on the given \a object, or on the Global
3459   Object if no object is specified.
3460
3461   The relation between Qt Script translator functions and C++ translator
3462   functions is described in the following table:
3463
3464     \table
3465     \header \o Script Function \o Corresponding C++ Function
3466     \row    \o qsTr()       \o QObject::tr()
3467     \row    \o QT_TR_NOOP() \o QT_TR_NOOP()
3468     \row    \o qsTranslate() \o QCoreApplication::translate()
3469     \row    \o QT_TRANSLATE_NOOP() \o QT_TRANSLATE_NOOP()
3470     \row    \o qsTrId() (since 4.7) \o qtTrId()
3471     \row    \o QT_TRID_NOOP() (since 4.7) \o QT_TRID_NOOP()
3472     \endtable
3473
3474   \sa {Internationalization with Qt}
3475 */
3476 void QScriptEngine::installTranslatorFunctions(const QScriptValue &object)
3477 {
3478     Q_D(QScriptEngine);
3479     QScript::APIShim shim(d);
3480     JSC::ExecState* exec = d->currentFrame;
3481     JSC::JSValue jscObject = d->scriptValueToJSCValue(object);
3482     JSC::JSGlobalObject *glob = d->originalGlobalObject();
3483     if (!jscObject || !jscObject.isObject())
3484         jscObject = d->globalObject();
3485 //    unsigned attribs = JSC::DontEnum;
3486     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 5, JSC::Identifier(exec, "qsTranslate"), QScript::functionQsTranslate));
3487     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 2, JSC::Identifier(exec, "QT_TRANSLATE_NOOP"), QScript::functionQsTranslateNoOp));
3488     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 3, JSC::Identifier(exec, "qsTr"), QScript::functionQsTr));
3489     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TR_NOOP"), QScript::functionQsTrNoOp));
3490     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "qsTrId"), QScript::functionQsTrId));
3491     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TRID_NOOP"), QScript::functionQsTrIdNoOp));
3492
3493     glob->stringPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "arg"), QScript::stringProtoFuncArg));
3494 }
3495
3496 /*!
3497     Imports the given \a extension into this QScriptEngine.  Returns
3498     undefinedValue() if the extension was successfully imported. You
3499     can call hasUncaughtException() to check if an error occurred; in
3500     that case, the return value is the value that was thrown by the
3501     exception (usually an \c{Error} object).
3502
3503     QScriptEngine ensures that a particular extension is only imported
3504     once; subsequent calls to importExtension() with the same extension
3505     name will do nothing and return undefinedValue().
3506
3507     \sa availableExtensions(), QScriptExtensionPlugin, {Creating QtScript Extensions}
3508 */
3509 QScriptValue QScriptEngine::importExtension(const QString &extension)
3510 {
3511 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
3512     Q_UNUSED(extension);
3513 #else
3514     Q_D(QScriptEngine);
3515     QScript::APIShim shim(d);
3516     if (d->importedExtensions.contains(extension))
3517         return undefinedValue(); // already imported
3518
3519     QScriptContext *context = currentContext();
3520     QCoreApplication *app = QCoreApplication::instance();
3521     if (!app)
3522         return context->throwError(QLatin1String("No application object"));
3523
3524     QObjectList staticPlugins = QPluginLoader::staticInstances();
3525     QStringList libraryPaths = app->libraryPaths();
3526     QString dot = QLatin1String(".");
3527     QStringList pathComponents = extension.split(dot);
3528     QString initDotJs = QLatin1String("__init__.js");
3529
3530     QString ext;
3531     for (int i = 0; i < pathComponents.count(); ++i) {
3532         if (!ext.isEmpty())
3533             ext.append(dot);
3534         ext.append(pathComponents.at(i));
3535         if (d->importedExtensions.contains(ext))
3536             continue; // already imported
3537
3538         if (d->extensionsBeingImported.contains(ext)) {
3539             return context->throwError(QString::fromLatin1("recursive import of %0")
3540                                        .arg(extension));
3541         }
3542         d->extensionsBeingImported.insert(ext);
3543
3544         QScriptExtensionInterface *iface = 0;
3545         QString initjsContents;
3546         QString initjsFileName;
3547
3548         // look for the extension in static plugins
3549         for (int j = 0; j < staticPlugins.size(); ++j) {
3550             iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
3551             if (!iface)
3552                 continue;
3553             if (iface->keys().contains(ext))
3554