1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "config.h"
41 #include "qscriptengine.h"
42 #include "qscriptsyntaxchecker_p.h"
43 
44 #include "qscriptengine_p.h"
45 #include "qscriptengineagent_p.h"
46 #include "qscriptcontext_p.h"
47 #include "qscriptstring_p.h"
48 #include "qscriptvalue_p.h"
49 #include "qscriptvalueiterator.h"
50 #include "qscriptclass.h"
51 #include "qscriptcontextinfo.h"
52 #include "qscriptprogram.h"
53 #include "qscriptprogram_p.h"
54 #include "qdebug.h"
55 
56 #include <QtCore/qstringlist.h>
57 #include <QtCore/qshareddata.h>
58 #include <QtCore/qmetaobject.h>
59 
60 #include <math.h>
61 #include <algorithm>
62 
63 #include "CodeBlock.h"
64 #include "Error.h"
65 #include "Interpreter.h"
66 
67 #include "ExceptionHelpers.h"
68 #include "PrototypeFunction.h"
69 #include "InitializeThreading.h"
70 #include "ObjectPrototype.h"
71 #include "SourceCode.h"
72 #include "FunctionPrototype.h"
73 #include "TimeoutChecker.h"
74 #include "JSFunction.h"
75 #include "Parser.h"
76 #include "PropertyNameArray.h"
77 #include "Operations.h"
78 
79 #include "bridge/qscriptfunction_p.h"
80 #include "bridge/qscriptclassobject_p.h"
81 #include "bridge/qscriptvariant_p.h"
82 #include "bridge/qscriptqobject_p.h"
83 #include "bridge/qscriptglobalobject_p.h"
84 #include "bridge/qscriptactivationobject_p.h"
85 #include "bridge/qscriptstaticscopeobject_p.h"
86 
87 #ifndef QT_NO_QOBJECT
88 #include <QtCore/qcoreapplication.h>
89 #include <QtCore/qdir.h>
90 #include <QtCore/qfile.h>
91 #include <QtCore/qfileinfo.h>
92 #include <QtCore/qpluginloader.h>
93 #include <QtCore/qset.h>
94 #include <QtCore/qtextstream.h>
95 #include "qscriptextensioninterface.h"
96 #endif
97 
98 #include <stdlib.h>
99 
100 Q_DECLARE_METATYPE(QScriptValue)
101 #ifndef QT_NO_QOBJECT
102 Q_DECLARE_METATYPE(QObjectList)
103 #endif
104 Q_DECLARE_METATYPE(QList<int>)
105 
106 QT_BEGIN_NAMESPACE
107 
108 /*!
109   \since 4.3
110   \class QScriptEngine
111   \reentrant
112   \inmodule QtScript
113 
114   \brief The QScriptEngine class provides an environment for evaluating Qt Script code.
115 
116   \ingroup script
117 
118   See the \l{Qt Script} documentation for information about the Qt Script language,
119   and how to get started with scripting your C++ application.
120 
121   \section1 Evaluating Scripts
122 
123   Use evaluate() to evaluate script code; this is the C++ equivalent
124   of the built-in script function \c{eval()}.
125 
126   \snippet code/src_script_qscriptengine.cpp 0
127 
128   evaluate() returns a QScriptValue that holds the result of the
129   evaluation. The QScriptValue class provides functions for converting
130   the result to various C++ types (e.g. QScriptValue::toString()
131   and QScriptValue::toNumber()).
132 
133   The following code snippet shows how a script function can be
134   defined and then invoked from C++ using QScriptValue::call():
135 
136   \snippet code/src_script_qscriptengine.cpp 1
137 
138   As can be seen from the above snippets, a script is provided to the
139   engine in the form of a string. One common way of loading scripts is
140   by reading the contents of a file and passing it to evaluate():
141 
142   \snippet code/src_script_qscriptengine.cpp 2
143 
144   Here we pass the name of the file as the second argument to
145   evaluate().  This does not affect evaluation in any way; the second
146   argument is a general-purpose string that is used to identify the
147   script for debugging purposes (for example, our filename will now
148   show up in any uncaughtExceptionBacktrace() involving the script).
149 
150   \section1 Engine Configuration
151 
152   The globalObject() function returns the \b {Global Object}
153   associated with the script engine. Properties of the Global Object
154   are accessible from any script code (i.e. they are global
155   variables). Typically, before evaluating "user" scripts, you will
156   want to configure a script engine by adding one or more properties
157   to the Global Object:
158 
159   \snippet code/src_script_qscriptengine.cpp 3
160 
161   Adding custom properties to the scripting environment is one of the
162   standard means of providing a scripting API that is specific to your
163   application. Usually these custom properties are objects created by
164   the newQObject() or newObject() functions, or constructor functions
165   created by newFunction().
166 
167   \section1 Script Exceptions
168 
169   evaluate() can throw a script exception (e.g. due to a syntax
170   error); in that case, the return value is the value that was thrown
171   (typically an \c{Error} object). You can check whether the
172   evaluation caused an exception by calling hasUncaughtException(). In
173   that case, you can call toString() on the error object to obtain an
174   error message. The current uncaught exception is also available
175   through uncaughtException().
176   Calling clearExceptions() will cause any uncaught exceptions to be
177   cleared.
178 
179   \snippet code/src_script_qscriptengine.cpp 4
180 
181   The checkSyntax() function can be used to determine whether code can be
182   usefully passed to evaluate().
183 
184   \section1 Script Object Creation
185 
186   Use newObject() to create a standard Qt Script object; this is the
187   C++ equivalent of the script statement \c{new Object()}. You can use
188   the object-specific functionality in QScriptValue to manipulate the
189   script object (e.g. QScriptValue::setProperty()). Similarly, use
190   newArray() to create a Qt Script array object. Use newDate() to
191   create a \c{Date} object, and newRegExp() to create a \c{RegExp}
192   object.
193 
194   \section1 QObject Integration
195 
196   Use newQObject() to wrap a QObject (or subclass)
197   pointer. newQObject() returns a proxy script object; properties,
198   children, and signals and slots of the QObject are available as
199   properties of the proxy object. No binding code is needed because it
200   is done dynamically using the Qt meta object system.
201 
202   \snippet code/src_script_qscriptengine.cpp 5
203 
204   Use qScriptConnect() to connect a C++ signal to a script function;
205   this is the Qt Script equivalent of QObject::connect().  When a
206   script function is invoked in response to a C++ signal, it can cause
207   a script exception; you can connect to the signalHandlerException()
208   signal to catch such an exception.
209 
210   Use newQMetaObject() to wrap a QMetaObject; this gives you a "script
211   representation" of a QObject-based class. newQMetaObject() returns a
212   proxy script object; enum values of the class are available as
213   properties of the proxy object. You can also specify a function that
214   will be used to construct objects of the class (e.g.  when the
215   constructor is invoked from a script). For classes that have a
216   "standard" Qt constructor, Qt Script can provide a default script
217   constructor for you; see scriptValueFromQMetaObject().
218 
219   See \l{Making Applications Scriptable} for more information on
220   the QObject integration.
221 
222   \section1 Support for Custom C++ Types
223 
224   Use newVariant() to wrap a QVariant. This can be used to store
225   values of custom (non-QObject) C++ types that have been registered
226   with the Qt meta-type system. To make such types scriptable, you
227   typically associate a prototype (delegate) object with the C++ type
228   by calling setDefaultPrototype(); the prototype object defines the
229   scripting API for the C++ type. Unlike the QObject integration,
230   there is no automatic binding possible here; i.e. you have to create
231   the scripting API yourself, for example by using the QScriptable
232   class.
233 
234   Use fromScriptValue() to cast from a QScriptValue to another type,
235   and toScriptValue() to create a QScriptValue from another value.
236   You can specify how the conversion of C++ types is to be performed
237   with qScriptRegisterMetaType() and qScriptRegisterSequenceMetaType().
238   By default, Qt Script will use QVariant to store values of custom
239   types.
240 
241   \section1 Importing Extensions
242 
243   Use importExtension() to import plugin-based extensions into the
244   engine. Call availableExtensions() to obtain a list naming all the
245   available extensions, and importedExtensions() to obtain a list
246   naming only those extensions that have been imported.
247 
248   Call pushContext() to open up a new variable scope, and popContext()
249   to close the current scope. This is useful if you are implementing
250   an extension that evaluates script code containing temporary
251   variable definitions (e.g. \c{var foo = 123;}) that are safe to
252   discard when evaluation has completed.
253 
254   \section1 Native Functions
255 
256   Use newFunction() to wrap native (C++) functions, including
257   constructors for your own custom types, so that these can be invoked
258   from script code. Such functions must have the signature
259   QScriptEngine::FunctionSignature. You may then pass the function as
260   argument to newFunction(). Here is an example of a function that
261   returns the sum of its first two arguments:
262 
263   \snippet code/src_script_qscriptengine.cpp 6
264 
265   To expose this function to script code, you can set it as a property
266   of the Global Object:
267 
268   \snippet code/src_script_qscriptengine.cpp 7
269 
270   Once this is done, script code can call your function in the exact
271   same manner as a "normal" script function:
272 
273   \snippet code/src_script_qscriptengine.cpp 8
274 
275   \section1 Long-running Scripts
276 
277   If you need to evaluate possibly long-running scripts from the main
278   (GUI) thread, you should first call setProcessEventsInterval() to
279   make sure that the GUI stays responsive. You can abort a currently
280   running script by calling abortEvaluation(). You can determine
281   whether an engine is currently running a script by calling
282   isEvaluating().
283 
284   \section1 Garbage Collection
285 
286   Qt Script objects may be garbage collected when they are no longer
287   referenced. There is no guarantee as to when automatic garbage
288   collection will take place.
289 
290   The collectGarbage() function can be called to explicitly request
291   garbage collection.
292 
293   The reportAdditionalMemoryCost() function can be called to indicate
294   that a Qt Script object occupies memory that isn't managed by the
295   scripting environment. Reporting the additional cost makes it more
296   likely that the garbage collector will be triggered. This can be
297   useful, for example, when many custom, native Qt Script objects are
298   allocated.
299 
300   \section1 Core Debugging/Tracing Facilities
301 
302   Since Qt 4.4, you can be notified of events pertaining to script
303   execution (e.g. script function calls and statement execution)
304   through the QScriptEngineAgent interface; see the setAgent()
305   function. This can be used to implement debugging and profiling of a
306   QScriptEngine.
307 
308   \sa QScriptValue, QScriptContext, QScriptEngineAgent
309 
310 */
311 
312 /*!
313     \enum QScriptEngine::ValueOwnership
314 
315     This enum specifies the ownership when wrapping a C++ value, e.g. by using newQObject().
316 
317     \value QtOwnership The standard Qt ownership rules apply, i.e. the
318     associated object will never be explicitly deleted by the script
319     engine. This is the default. (QObject ownership is explained in
320     \l{Object Trees & Ownership}.)
321 
322     \value ScriptOwnership The value is owned by the script
323     environment. The associated data will be deleted when appropriate
324     (i.e. after the garbage collector has discovered that there are no
325     more live references to the value).
326 
327     \value AutoOwnership If the associated object has a parent, the Qt
328     ownership rules apply (QtOwnership); otherwise, the object is
329     owned by the script environment (ScriptOwnership).
330 
331 */
332 
333 /*!
334     \enum  QScriptEngine::QObjectWrapOption
335 
336     These flags specify options when wrapping a QObject pointer with newQObject().
337 
338     \value ExcludeChildObjects The script object will not expose child objects as properties.
339     \value ExcludeSuperClassMethods The script object will not expose signals and slots inherited from the superclass.
340     \value ExcludeSuperClassProperties The script object will not expose properties inherited from the superclass.
341     \value ExcludeSuperClassContents Shorthand form for ExcludeSuperClassMethods | ExcludeSuperClassProperties
342     \value ExcludeDeleteLater The script object will not expose the QObject::deleteLater() slot.
343     \value ExcludeSlots The script object will not expose the QObject's slots.
344     \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.
345     \value PreferExistingWrapperObject If a wrapper object with the requested configuration already exists, return that object.
346     \value SkipMethodsInEnumeration Don't include methods (signals and slots) when enumerating the object's properties.
347 */
348 
349 class QScriptSyntaxCheckResultPrivate : public QSharedData
350 {
351 public:
QScriptSyntaxCheckResultPrivate()352     QScriptSyntaxCheckResultPrivate() {}
~QScriptSyntaxCheckResultPrivate()353     ~QScriptSyntaxCheckResultPrivate() {}
354 
355     QScriptSyntaxCheckResult::State state;
356     int errorColumnNumber;
357     int errorLineNumber;
358     QString errorMessage;
359 };
360 
361 class QScriptTypeInfo
362 {
363 public:
QScriptTypeInfo()364     QScriptTypeInfo() : signature(0, '\0'), marshal(0), demarshal(0)
365     { }
366 
367     QByteArray signature;
368     QScriptEngine::MarshalFunction marshal;
369     QScriptEngine::DemarshalFunction demarshal;
370     JSC::JSValue prototype;
371 };
372 
373 namespace QScript
374 {
375 
376 static const qsreal D32 = 4294967296.0;
377 
ToInt32(qsreal n)378 qint32 ToInt32(qsreal n)
379 {
380     if (qIsNaN(n) || qIsInf(n) || (n == 0))
381         return 0;
382 
383     qsreal sign = (n < 0) ? -1.0 : 1.0;
384     qsreal abs_n = fabs(n);
385 
386     n = ::fmod(sign * ::floor(abs_n), D32);
387     const double D31 = D32 / 2.0;
388 
389     if (sign == -1 && n < -D31)
390         n += D32;
391 
392     else if (sign != -1 && n >= D31)
393         n -= D32;
394 
395     return qint32 (n);
396 }
397 
ToUInt32(qsreal n)398 quint32 ToUInt32(qsreal n)
399 {
400     if (qIsNaN(n) || qIsInf(n) || (n == 0))
401         return 0;
402 
403     qsreal sign = (n < 0) ? -1.0 : 1.0;
404     qsreal abs_n = fabs(n);
405 
406     n = ::fmod(sign * ::floor(abs_n), D32);
407 
408     if (n < 0)
409         n += D32;
410 
411     return quint32 (n);
412 }
413 
ToUInt16(qsreal n)414 quint16 ToUInt16(qsreal n)
415 {
416     static const qsreal D16 = 65536.0;
417 
418     if (qIsNaN(n) || qIsInf(n) || (n == 0))
419         return 0;
420 
421     qsreal sign = (n < 0) ? -1.0 : 1.0;
422     qsreal abs_n = fabs(n);
423 
424     n = ::fmod(sign * ::floor(abs_n), D16);
425 
426     if (n < 0)
427         n += D16;
428 
429     return quint16 (n);
430 }
431 
ToInteger(qsreal n)432 qsreal ToInteger(qsreal n)
433 {
434     if (qIsNaN(n))
435         return 0;
436 
437     if (n == 0 || qIsInf(n))
438         return n;
439 
440     int sign = n < 0 ? -1 : 1;
441     return sign * ::floor(::fabs(n));
442 }
443 
444 #ifdef Q_CC_MSVC
445 // MSVC2008 crashes if these are inlined.
446 
ToString(qsreal value)447 QString ToString(qsreal value)
448 {
449     return JSC::UString::from(value);
450 }
451 
ToNumber(const QString & value)452 qsreal ToNumber(const QString &value)
453 {
454     return ((JSC::UString)value).toDouble();
455 }
456 
457 #endif
458 
459 static const qsreal MsPerSecond = 1000.0;
460 
MsFromTime(qsreal t)461 static inline int MsFromTime(qsreal t)
462 {
463     int r = int(::fmod(t, MsPerSecond));
464     return (r >= 0) ? r : r + int(MsPerSecond);
465 }
466 
467 /*!
468   \internal
469   Converts a JS date value (milliseconds) to a QDateTime (local time).
470 */
MsToDateTime(JSC::ExecState * exec,qsreal t)471 QDateTime MsToDateTime(JSC::ExecState *exec, qsreal t)
472 {
473     if (qIsNaN(t))
474         return QDateTime();
475     JSC::GregorianDateTime tm;
476     JSC::msToGregorianDateTime(exec, t, /*output UTC=*/true, tm);
477     int ms = MsFromTime(t);
478     QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
479                                        QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
480     return convertedUTC.toLocalTime();
481 }
482 
483 /*!
484   \internal
485   Converts a QDateTime to a JS date value (milliseconds).
486 */
DateTimeToMs(JSC::ExecState * exec,const QDateTime & dt)487 qsreal DateTimeToMs(JSC::ExecState *exec, const QDateTime &dt)
488 {
489     if (!dt.isValid())
490         return qSNaN();
491     QDateTime utc = dt.toUTC();
492     QDate date = utc.date();
493     QTime time = utc.time();
494     JSC::GregorianDateTime tm;
495     tm.year = date.year() - 1900;
496     tm.month = date.month() - 1;
497     tm.monthDay = date.day();
498     tm.weekDay = date.dayOfWeek();
499     tm.yearDay = date.dayOfYear();
500     tm.hour = time.hour();
501     tm.minute = time.minute();
502     tm.second = time.second();
503     return JSC::gregorianDateTimeToMS(exec, tm, time.msec(), /*inputIsUTC=*/true);
504 }
505 
mark(JSC::MarkStack & markStack)506 void GlobalClientData::mark(JSC::MarkStack& markStack)
507 {
508     engine->mark(markStack);
509 }
510 
uncaughtException(JSC::ExecState * exec,unsigned bytecodeOffset,JSC::JSValue value)511 void GlobalClientData::uncaughtException(JSC::ExecState* exec, unsigned bytecodeOffset,
512                                          JSC::JSValue value)
513 {
514     engine->uncaughtException(exec, bytecodeOffset, value);
515 }
516 
517 class TimeoutCheckerProxy : public JSC::TimeoutChecker
518 {
519 public:
TimeoutCheckerProxy(const JSC::TimeoutChecker & originalChecker)520     TimeoutCheckerProxy(const JSC::TimeoutChecker& originalChecker)
521         : JSC::TimeoutChecker(originalChecker)
522         , m_shouldProcessEvents(false)
523         , m_shouldAbortEvaluation(false)
524     {}
525 
setShouldProcessEvents(bool shouldProcess)526     void setShouldProcessEvents(bool shouldProcess) { m_shouldProcessEvents = shouldProcess; }
setShouldAbort(bool shouldAbort)527     void setShouldAbort(bool shouldAbort) { m_shouldAbortEvaluation = shouldAbort; }
shouldAbort()528     bool shouldAbort() { return m_shouldAbortEvaluation; }
529 
didTimeOut(JSC::ExecState * exec)530     virtual bool didTimeOut(JSC::ExecState* exec)
531     {
532         if (JSC::TimeoutChecker::didTimeOut(exec))
533             return true;
534 
535         if (m_shouldProcessEvents)
536             QCoreApplication::processEvents();
537 
538         return m_shouldAbortEvaluation;
539     }
540 
541 private:
542     bool m_shouldProcessEvents;
543     bool m_shouldAbortEvaluation;
544 };
545 
toDigit(char c)546 static int toDigit(char c)
547 {
548     if ((c >= '0') && (c <= '9'))
549         return c - '0';
550     else if ((c >= 'a') && (c <= 'z'))
551         return 10 + c - 'a';
552     else if ((c >= 'A') && (c <= 'Z'))
553         return 10 + c - 'A';
554     return -1;
555 }
556 
integerFromString(const char * buf,int size,int radix)557 qsreal integerFromString(const char *buf, int size, int radix)
558 {
559     if (size == 0)
560         return qSNaN();
561 
562     qsreal sign = 1.0;
563     int i = 0;
564     if (buf[0] == '+') {
565         ++i;
566     } else if (buf[0] == '-') {
567         sign = -1.0;
568         ++i;
569     }
570 
571     if (((size-i) >= 2) && (buf[i] == '0')) {
572         if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
573             && (radix < 34)) {
574             if ((radix != 0) && (radix != 16))
575                 return 0;
576             radix = 16;
577             i += 2;
578         } else {
579             if (radix == 0) {
580                 radix = 8;
581                 ++i;
582             }
583         }
584     } else if (radix == 0) {
585         radix = 10;
586     }
587 
588     int j = i;
589     for ( ; i < size; ++i) {
590         int d = toDigit(buf[i]);
591         if ((d == -1) || (d >= radix))
592             break;
593     }
594     qsreal result;
595     if (j == i) {
596         if (!qstrcmp(buf, "Infinity"))
597             result = qInf();
598         else
599             result = qSNaN();
600     } else {
601         result = 0;
602         qsreal multiplier = 1;
603         for (--i ; i >= j; --i, multiplier *= radix)
604             result += toDigit(buf[i]) * multiplier;
605     }
606     result *= sign;
607     return result;
608 }
609 
integerFromString(const QString & str,int radix)610 qsreal integerFromString(const QString &str, int radix)
611 {
612     QByteArray ba = str.trimmed().toUtf8();
613     return integerFromString(ba.constData(), ba.size(), radix);
614 }
615 
isFunction(JSC::JSValue value)616 bool isFunction(JSC::JSValue value)
617 {
618     if (!value || !value.isObject())
619         return false;
620     JSC::CallData callData;
621     return (JSC::asObject(value)->getCallData(callData) != JSC::CallTypeNone);
622 }
623 
624 static JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
625 static JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
626 
functionDisconnect(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)627 JSC::JSValue JSC_HOST_CALL functionDisconnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
628 {
629 #ifndef QT_NO_QOBJECT
630     if (args.size() == 0) {
631         return JSC::throwError(exec, JSC::GeneralError, "Function.prototype.disconnect: no arguments given");
632     }
633 
634     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
635         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: this object is not a signal");
636     }
637 
638     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
639 
640     const QMetaObject *meta = qtSignal->metaObject();
641     if (!meta) {
642         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.discconnect: cannot disconnect from deleted QObject");
643     }
644 
645     QMetaMethod sig = meta->method(qtSignal->initialIndex());
646     if (sig.methodType() != QMetaMethod::Signal) {
647         QString message = QString::fromLatin1("Function.prototype.disconnect: %0::%1 is not a signal")
648                           .arg(QLatin1String(qtSignal->metaObject()->className()))
649                           .arg(QLatin1String(sig.methodSignature().constData()));
650         return JSC::throwError(exec, JSC::TypeError, message);
651     }
652 
653     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
654 
655     JSC::JSValue receiver;
656     JSC::JSValue slot;
657     JSC::JSValue arg0 = args.at(0);
658     if (args.size() < 2) {
659         slot = arg0;
660     } else {
661         receiver = arg0;
662         JSC::JSValue arg1 = args.at(1);
663         if (isFunction(arg1))
664             slot = arg1;
665         else {
666             QScript::SaveFrameHelper saveFrame(engine, exec);
667             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
668             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
669         }
670     }
671 
672     if (!isFunction(slot)) {
673         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.disconnect: target is not a function");
674     }
675 
676     bool ok = engine->scriptDisconnect(thisObject, receiver, slot);
677     if (!ok) {
678         QString message = QString::fromLatin1("Function.prototype.disconnect: failed to disconnect from %0::%1")
679                           .arg(QLatin1String(qtSignal->metaObject()->className()))
680                           .arg(QLatin1String(sig.methodSignature().constData()));
681         return JSC::throwError(exec, JSC::GeneralError, message);
682     }
683     return JSC::jsUndefined();
684 #else
685     Q_UNUSED(eng);
686     return context->throwError(QScriptContext::TypeError,
687                                QLatin1String("Function.prototype.disconnect"));
688 #endif // QT_NO_QOBJECT
689 }
690 
functionConnect(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)691 JSC::JSValue JSC_HOST_CALL functionConnect(JSC::ExecState *exec, JSC::JSObject * /*callee*/, JSC::JSValue thisObject, const JSC::ArgList &args)
692 {
693 #ifndef QT_NO_QOBJECT
694     if (args.size() == 0) {
695         return JSC::throwError(exec, JSC::GeneralError,"Function.prototype.connect: no arguments given");
696     }
697 
698     if (!JSC::asObject(thisObject)->inherits(&QScript::QtFunction::info)) {
699         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: this object is not a signal");
700     }
701 
702     QScript::QtFunction *qtSignal = static_cast<QScript::QtFunction*>(JSC::asObject(thisObject));
703 
704     const QMetaObject *meta = qtSignal->metaObject();
705     if (!meta) {
706         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: cannot connect to deleted QObject");
707     }
708 
709     QMetaMethod sig = meta->method(qtSignal->initialIndex());
710     if (sig.methodType() != QMetaMethod::Signal) {
711         QString message = QString::fromLatin1("Function.prototype.connect: %0::%1 is not a signal")
712                           .arg(QLatin1String(qtSignal->metaObject()->className()))
713                           .arg(QLatin1String(sig.methodSignature().constData()));
714         return JSC::throwError(exec, JSC::TypeError, message);
715     }
716 
717     {
718         QList<int> overloads = qtSignal->overloadedIndexes();
719         if (!overloads.isEmpty()) {
720             overloads.append(qtSignal->initialIndex());
721             QByteArray signature = sig.methodSignature();
722             QString message = QString::fromLatin1("Function.prototype.connect: ambiguous connect to %0::%1(); candidates are\n")
723                               .arg(QLatin1String(qtSignal->metaObject()->className()))
724                               .arg(QLatin1String(signature.left(signature.indexOf('('))));
725             for (int i = 0; i < overloads.size(); ++i) {
726                 QMetaMethod mtd = meta->method(overloads.at(i));
727                 message.append(QString::fromLatin1("    %0\n").arg(QString::fromLatin1(mtd.methodSignature().constData())));
728             }
729             message.append(QString::fromLatin1("Use e.g. object['%0'].connect() to connect to a particular overload")
730                            .arg(QLatin1String(signature)));
731             return JSC::throwError(exec, JSC::GeneralError, message);
732         }
733     }
734 
735     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
736 
737     JSC::JSValue receiver;
738     JSC::JSValue slot;
739     JSC::JSValue arg0 = args.at(0);
740     if (args.size() < 2) {
741         slot = arg0;
742     } else {
743         receiver = arg0;
744         JSC::JSValue arg1 = args.at(1);
745         if (isFunction(arg1))
746             slot = arg1;
747         else {
748             QScript::SaveFrameHelper saveFrame(engine, exec);
749             JSC::UString propertyName = QScriptEnginePrivate::toString(exec, arg1);
750             slot = QScriptEnginePrivate::property(exec, arg0, propertyName, QScriptValue::ResolvePrototype);
751         }
752     }
753 
754     if (!isFunction(slot)) {
755         return JSC::throwError(exec, JSC::TypeError, "Function.prototype.connect: target is not a function");
756     }
757 
758     bool ok = engine->scriptConnect(thisObject, receiver, slot, Qt::AutoConnection);
759     if (!ok) {
760         QString message = QString::fromLatin1("Function.prototype.connect: failed to connect to %0::%1")
761                           .arg(QLatin1String(qtSignal->metaObject()->className()))
762                           .arg(QLatin1String(sig.methodSignature().constData()));
763         return JSC::throwError(exec, JSC::GeneralError, message);
764     }
765     return JSC::jsUndefined();
766 #else
767     Q_UNUSED(eng);
768     Q_UNUSED(classInfo);
769     return context->throwError(QScriptContext::TypeError,
770                                QLatin1String("Function.prototype.connect"));
771 #endif // QT_NO_QOBJECT
772 }
773 
774 static JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
775 static JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
776 static JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
777 
functionPrint(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)778 JSC::JSValue JSC_HOST_CALL functionPrint(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList& args)
779 {
780     QString result;
781     for (unsigned i = 0; i < args.size(); ++i) {
782         if (i != 0)
783             result.append(QLatin1Char(' '));
784         QString s(args.at(i).toString(exec));
785         if (exec->hadException())
786             break;
787         result.append(s);
788     }
789     if (exec->hadException())
790         return exec->exception();
791     qDebug("%s", qPrintable(result));
792     return JSC::jsUndefined();
793 }
794 
functionGC(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList &)795 JSC::JSValue JSC_HOST_CALL functionGC(JSC::ExecState* exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
796 {
797     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
798     engine->collectGarbage();
799     return JSC::jsUndefined();
800 }
801 
functionVersion(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList &)802 JSC::JSValue JSC_HOST_CALL functionVersion(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&)
803 {
804     return JSC::JSValue(exec, 1);
805 }
806 
807 #ifndef QT_NO_TRANSLATION
808 
809 static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
810 static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
811 static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
812 static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
813 static JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
814 static JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
815 
functionQsTranslate(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)816 JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
817 {
818     if (args.size() < 2)
819         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate() requires at least two arguments");
820     if (!args.at(0).isString())
821         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): first argument (context) must be a string");
822     if (!args.at(1).isString())
823         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): second argument (text) must be a string");
824     if ((args.size() > 2) && !args.at(2).isString())
825         return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): third argument (comment) must be a string");
826 
827     int n = -1;
828     if ((args.size() > 3)) {
829         if (args.at(3).isString()) {
830             qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated");
831             if (args.size() > 4) {
832                 if (args.at(4).isNumber())
833                     n = args.at(4).toInt32(exec);
834                 else
835                     return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fifth argument (n) must be a number");
836             }
837         } else if (args.at(3).isNumber()) {
838             n = args.at(3).toInt32(exec);
839         } else {
840             return JSC::throwError(exec, JSC::GeneralError, "qsTranslate(): fourth argument (n) must be a number");
841         }
842     }
843 #ifndef QT_NO_QOBJECT
844     JSC::UString context = args.at(0).toString(exec);
845 #endif
846     JSC::UString text = args.at(1).toString(exec);
847 #ifndef QT_NO_QOBJECT
848     JSC::UString comment;
849     if (args.size() > 2)
850         comment = args.at(2).toString(exec);
851 #endif
852     JSC::UString result;
853 #ifndef QT_NO_QOBJECT
854     result = QCoreApplication::translate(context.UTF8String().c_str(),
855                                          text.UTF8String().c_str(),
856                                          comment.UTF8String().c_str(),
857                                          n);
858 #else
859     result = text;
860 #endif
861     return JSC::jsString(exec, result);
862 }
863 
functionQsTranslateNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)864 JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
865 {
866     if (args.size() < 2)
867         return JSC::jsUndefined();
868     return args.at(1);
869 }
870 
functionQsTr(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)871 JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
872 {
873     if (args.size() < 1)
874         return JSC::throwError(exec, JSC::GeneralError, "qsTr() requires at least one argument");
875     if (!args.at(0).isString())
876         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): first argument (text) must be a string");
877     if ((args.size() > 1) && !args.at(1).isString())
878         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): second argument (comment) must be a string");
879     if ((args.size() > 2) && !args.at(2).isNumber())
880         return JSC::throwError(exec, JSC::GeneralError, "qsTr(): third argument (n) must be a number");
881 #ifndef QT_NO_QOBJECT
882     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
883     JSC::UString context;
884     // The first non-empty source URL in the call stack determines the translation context.
885     {
886         JSC::ExecState *frame = exec->callerFrame()->removeHostCallFrameFlag();
887         while (frame) {
888             if (frame->codeBlock() && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)
889                 && frame->codeBlock()->source()
890                 && !frame->codeBlock()->source()->url().isEmpty()) {
891                 context = engine->translationContextFromUrl(frame->codeBlock()->source()->url());
892                 break;
893             }
894             frame = frame->callerFrame()->removeHostCallFrameFlag();
895         }
896     }
897 #endif
898     JSC::UString text = args.at(0).toString(exec);
899 #ifndef QT_NO_QOBJECT
900     JSC::UString comment;
901     if (args.size() > 1)
902         comment = args.at(1).toString(exec);
903     int n = -1;
904     if (args.size() > 2)
905         n = args.at(2).toInt32(exec);
906 #endif
907     JSC::UString result;
908 #ifndef QT_NO_QOBJECT
909     result = QCoreApplication::translate(context.UTF8String().c_str(),
910                                          text.UTF8String().c_str(),
911                                          comment.UTF8String().c_str(),
912                                          n);
913 #else
914     result = text;
915 #endif
916     return JSC::jsString(exec, result);
917 }
918 
functionQsTrNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)919 JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
920 {
921     if (args.size() < 1)
922         return JSC::jsUndefined();
923     return args.at(0);
924 }
925 
functionQsTrId(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)926 JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
927 {
928     if (args.size() < 1)
929         return JSC::throwError(exec, JSC::GeneralError, "qsTrId() requires at least one argument");
930     if (!args.at(0).isString())
931         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): first argument (id) must be a string");
932     if ((args.size() > 1) && !args.at(1).isNumber())
933         return JSC::throwError(exec, JSC::TypeError, "qsTrId(): second argument (n) must be a number");
934     JSC::UString id = args.at(0).toString(exec);
935     int n = -1;
936     if (args.size() > 1)
937         n = args.at(1).toInt32(exec);
938     return JSC::jsString(exec, qtTrId(id.UTF8String().c_str(), n));
939 }
940 
functionQsTrIdNoOp(JSC::ExecState *,JSC::JSObject *,JSC::JSValue,const JSC::ArgList & args)941 JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args)
942 {
943     if (args.size() < 1)
944         return JSC::jsUndefined();
945     return args.at(0);
946 }
947 #endif // QT_NO_TRANSLATION
948 
949 static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&);
950 
stringProtoFuncArg(JSC::ExecState * exec,JSC::JSObject *,JSC::JSValue thisObject,const JSC::ArgList & args)951 JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args)
952 {
953     QString value(thisObject.toString(exec));
954     JSC::JSValue arg = (args.size() != 0) ? args.at(0) : JSC::jsUndefined();
955     QString result;
956     if (arg.isString())
957         result = value.arg(arg.toString(exec));
958     else if (arg.isNumber())
959         result = value.arg(arg.toNumber(exec));
960     return JSC::jsString(exec, result);
961 }
962 
963 
964 #if !defined(QT_NO_QOBJECT) && !defined(QT_NO_LIBRARY)
__setupPackage__(QScriptContext * ctx,QScriptEngine * eng)965 static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng)
966 {
967     QString path = ctx->argument(0).toString();
968     QStringList components = path.split(QLatin1Char('.'));
969     QScriptValue o = eng->globalObject();
970     for (int i = 0; i < components.count(); ++i) {
971         QString name = components.at(i);
972         QScriptValue oo = o.property(name);
973         if (!oo.isValid()) {
974             oo = eng->newObject();
975             o.setProperty(name, oo);
976         }
977         o = oo;
978     }
979     return o;
980 }
981 #endif
982 
983 } // namespace QScript
984 
QScriptEnginePrivate()985 QScriptEnginePrivate::QScriptEnginePrivate()
986     : originalGlobalObjectProxy(0), currentFrame(0),
987       qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0),
988       activeAgent(0), agentLineNumber(-1),
989       registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0),
990       registeredScriptStrings(0), processEventsInterval(-1), inEval(false),
991       uncaughtExceptionLineNumber(-1)
992 {
993     qMetaTypeId<QScriptValue>();
994     qMetaTypeId<QList<int> >();
995 #ifndef QT_NO_QOBJECT
996     qMetaTypeId<QObjectList>();
997 #endif
998 
999     if (!QCoreApplication::instance()) {
1000         qFatal("QScriptEngine: Must construct a Q(Core)Application before a QScriptEngine");
1001         return;
1002     }
1003     JSC::initializeThreading();
1004     JSC::IdentifierTable *oldTable = JSC::currentIdentifierTable();
1005     globalData = JSC::JSGlobalData::create().releaseRef();
1006     globalData->clientData = new QScript::GlobalClientData(this);
1007     JSC::JSGlobalObject *globalObject = new (globalData)QScript::GlobalObject();
1008 
1009     JSC::ExecState* exec = globalObject->globalExec();
1010 
1011     scriptObjectStructure = QScriptObject::createStructure(globalObject->objectPrototype());
1012     staticScopeObjectStructure = QScriptStaticScopeObject::createStructure(JSC::jsNull());
1013 
1014     qobjectPrototype = new (exec) QScript::QObjectPrototype(exec, QScript::QObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
1015     qobjectWrapperObjectStructure = QScriptObject::createStructure(qobjectPrototype);
1016 
1017     qmetaobjectPrototype = new (exec) QScript::QMetaObjectPrototype(exec, QScript::QMetaObjectPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
1018     qmetaobjectWrapperObjectStructure = QScript::QMetaObjectWrapperObject::createStructure(qmetaobjectPrototype);
1019 
1020     variantPrototype = new (exec) QScript::QVariantPrototype(exec, QScript::QVariantPrototype::createStructure(globalObject->objectPrototype()), globalObject->prototypeFunctionStructure());
1021     variantWrapperObjectStructure = QScriptObject::createStructure(variantPrototype);
1022 
1023     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "print"), QScript::functionPrint));
1024     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "gc"), QScript::functionGC));
1025     globalObject->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 0, JSC::Identifier(exec, "version"), QScript::functionVersion));
1026 
1027     // ### rather than extending Function.prototype, consider creating a QtSignal.prototype
1028     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "disconnect"), QScript::functionDisconnect));
1029     globalObject->functionPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, globalObject->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "connect"), QScript::functionConnect));
1030 
1031     JSC::TimeoutChecker* originalChecker = globalData->timeoutChecker;
1032     globalData->timeoutChecker = new QScript::TimeoutCheckerProxy(*originalChecker);
1033     delete originalChecker;
1034 
1035     currentFrame = exec;
1036 
1037     cachedTranslationUrl = JSC::UString();
1038     cachedTranslationContext = JSC::UString();
1039     JSC::setCurrentIdentifierTable(oldTable);
1040 }
1041 
~QScriptEnginePrivate()1042 QScriptEnginePrivate::~QScriptEnginePrivate()
1043 {
1044     QScript::APIShim shim(this);
1045 
1046     //disconnect all loadedScripts and generate all jsc::debugger::scriptUnload events
1047     QHash<intptr_t,QScript::UStringSourceProviderWithFeedback*>::const_iterator it;
1048     for (it = loadedScripts.constBegin(); it != loadedScripts.constEnd(); ++it)
1049         it.value()->disconnectFromEngine();
1050 
1051     while (!ownedAgents.isEmpty())
1052         delete ownedAgents.takeFirst();
1053 
1054     detachAllRegisteredScriptPrograms();
1055     detachAllRegisteredScriptValues();
1056     detachAllRegisteredScriptStrings();
1057     qDeleteAll(m_qobjectData);
1058     qDeleteAll(m_typeInfos);
1059     globalData->heap.destroy();
1060     globalData->deref();
1061     while (freeScriptValues) {
1062         QScriptValuePrivate *p = freeScriptValues;
1063         freeScriptValues = p->next;
1064         free(p);
1065     }
1066 }
1067 
jscValueToVariant(JSC::ExecState * exec,JSC::JSValue value,int targetType)1068 QVariant QScriptEnginePrivate::jscValueToVariant(JSC::ExecState *exec, JSC::JSValue value, int targetType)
1069 {
1070     if (targetType == QMetaType::QVariant || uint(targetType) == QVariant::LastType)
1071         return toVariant(exec, value);
1072     QVariant v(targetType, (void *)0);
1073     if (convertValue(exec, value, targetType, v.data()))
1074         return v;
1075     if (isVariant(value)) {
1076         v = variantValue(value);
1077         if (v.canConvert(targetType)) {
1078             v.convert(targetType);
1079             return v;
1080         }
1081         QByteArray typeName = v.typeName();
1082         if (typeName.endsWith('*')
1083             && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
1084             return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
1085         }
1086     }
1087     return QVariant();
1088 }
1089 
arrayFromStringList(JSC::ExecState * exec,const QStringList & lst)1090 JSC::JSValue QScriptEnginePrivate::arrayFromStringList(JSC::ExecState *exec, const QStringList &lst)
1091 {
1092     JSC::JSValue arr =  newArray(exec, lst.size());
1093     for (int i = 0; i < lst.size(); ++i)
1094         setProperty(exec, arr, i, JSC::jsString(exec, lst.at(i)));
1095     return arr;
1096 }
1097 
stringListFromArray(JSC::ExecState * exec,JSC::JSValue arr)1098 QStringList QScriptEnginePrivate::stringListFromArray(JSC::ExecState *exec, JSC::JSValue arr)
1099 {
1100     QStringList lst;
1101     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1102     for (uint i = 0; i < len; ++i)
1103         lst.append(toString(exec, property(exec, arr, i)));
1104     return lst;
1105 }
1106 
arrayFromVariantList(JSC::ExecState * exec,const QVariantList & lst)1107 JSC::JSValue QScriptEnginePrivate::arrayFromVariantList(JSC::ExecState *exec, const QVariantList &lst)
1108 {
1109     JSC::JSValue arr = newArray(exec, lst.size());
1110     for (int i = 0; i < lst.size(); ++i)
1111         setProperty(exec, arr, i, jscValueFromVariant(exec, lst.at(i)));
1112     return arr;
1113 }
1114 
variantListFromArray(JSC::ExecState * exec,JSC::JSArray * arr)1115 QVariantList QScriptEnginePrivate::variantListFromArray(JSC::ExecState *exec, JSC::JSArray *arr)
1116 {
1117     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1118     if (eng->visitedConversionObjects.contains(arr))
1119         return QVariantList(); // Avoid recursion.
1120     eng->visitedConversionObjects.insert(arr);
1121     QVariantList lst;
1122     uint len = toUInt32(exec, property(exec, arr, exec->propertyNames().length));
1123     for (uint i = 0; i < len; ++i)
1124         lst.append(toVariant(exec, property(exec, arr, i)));
1125     eng->visitedConversionObjects.remove(arr);
1126     return lst;
1127 }
1128 
objectFromVariantMap(JSC::ExecState * exec,const QVariantMap & vmap)1129 JSC::JSValue QScriptEnginePrivate::objectFromVariantMap(JSC::ExecState *exec, const QVariantMap &vmap)
1130 {
1131     JSC::JSValue obj = JSC::constructEmptyObject(exec);
1132     QVariantMap::const_iterator it;
1133     for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1134         setProperty(exec, obj, it.key(), jscValueFromVariant(exec, it.value()));
1135     return obj;
1136 }
1137 
variantMapFromObject(JSC::ExecState * exec,JSC::JSObject * obj)1138 QVariantMap QScriptEnginePrivate::variantMapFromObject(JSC::ExecState *exec, JSC::JSObject *obj)
1139 {
1140     QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(exec);
1141     if (eng->visitedConversionObjects.contains(obj))
1142         return QVariantMap(); // Avoid recursion.
1143     eng->visitedConversionObjects.insert(obj);
1144     JSC::PropertyNameArray propertyNames(exec);
1145     obj->getOwnPropertyNames(exec, propertyNames, JSC::IncludeDontEnumProperties);
1146     QVariantMap vmap;
1147     JSC::PropertyNameArray::const_iterator it = propertyNames.begin();
1148     for( ; it != propertyNames.end(); ++it)
1149         vmap.insert(it->ustring(), toVariant(exec, property(exec, obj, *it)));
1150     eng->visitedConversionObjects.remove(obj);
1151     return vmap;
1152 }
1153 
defaultPrototype(int metaTypeId) const1154 JSC::JSValue QScriptEnginePrivate::defaultPrototype(int metaTypeId) const
1155 {
1156     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1157     if (!info)
1158         return JSC::JSValue();
1159     return info->prototype;
1160 }
1161 
setDefaultPrototype(int metaTypeId,JSC::JSValue prototype)1162 void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, JSC::JSValue prototype)
1163 {
1164     QScriptTypeInfo *info = m_typeInfos.value(metaTypeId);
1165     if (!info) {
1166         info = new QScriptTypeInfo();
1167         m_typeInfos.insert(metaTypeId, info);
1168     }
1169     info->prototype = prototype;
1170 }
1171 
originalGlobalObject() const1172 JSC::JSGlobalObject *QScriptEnginePrivate::originalGlobalObject() const
1173 {
1174     return globalData->head;
1175 }
1176 
customGlobalObject() const1177 JSC::JSObject *QScriptEnginePrivate::customGlobalObject() const
1178 {
1179     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1180     return glob->customGlobalObject;
1181 }
1182 
getOriginalGlobalObjectProxy()1183 JSC::JSObject *QScriptEnginePrivate::getOriginalGlobalObjectProxy()
1184 {
1185     if (!originalGlobalObjectProxy) {
1186         JSC::ExecState* exec = currentFrame;
1187         originalGlobalObjectProxy = new (exec)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1188     }
1189     return originalGlobalObjectProxy;
1190 }
1191 
globalObject() const1192 JSC::JSObject *QScriptEnginePrivate::globalObject() const
1193 {
1194     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1195     if (glob->customGlobalObject)
1196         return glob->customGlobalObject;
1197     return glob;
1198 }
1199 
setGlobalObject(JSC::JSObject * object)1200 void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object)
1201 {
1202     if (object == globalObject())
1203         return;
1204     QScript::GlobalObject *glob = static_cast<QScript::GlobalObject*>(originalGlobalObject());
1205     if (object == originalGlobalObjectProxy) {
1206         glob->customGlobalObject = 0;
1207         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1208         glob->setPrototype(originalGlobalObjectProxy->prototype());
1209     } else {
1210         Q_ASSERT(object != originalGlobalObject());
1211         glob->customGlobalObject = object;
1212         // Sync the internal prototype, since JSObject::prototype() is not virtual.
1213         glob->setPrototype(object->prototype());
1214     }
1215 }
1216 
1217 /*!
1218   \internal
1219 
1220   If the given \a value is the original global object, returns the custom
1221   global object or a proxy to the original global object; otherwise returns \a
1222   value.
1223 */
toUsableValue(JSC::JSValue value)1224 JSC::JSValue QScriptEnginePrivate::toUsableValue(JSC::JSValue value)
1225 {
1226     if (!value || !value.isObject() || !JSC::asObject(value)->isGlobalObject())
1227         return value;
1228     Q_ASSERT(JSC::asObject(value) == originalGlobalObject());
1229     if (customGlobalObject())
1230         return customGlobalObject();
1231     if (!originalGlobalObjectProxy)
1232         originalGlobalObjectProxy = new (currentFrame)QScript::OriginalGlobalObjectProxy(scriptObjectStructure, originalGlobalObject());
1233     return originalGlobalObjectProxy;
1234 }
1235 /*!
1236     \internal
1237     Return the 'this' value for a given context
1238 */
thisForContext(JSC::ExecState * frame)1239 JSC::JSValue QScriptEnginePrivate::thisForContext(JSC::ExecState *frame)
1240 {
1241     if (frame->codeBlock() != 0) {
1242         return frame->thisValue();
1243     } else if(frame == frame->lexicalGlobalObject()->globalExec()) {
1244         return frame->globalThisValue();
1245     } else {
1246         JSC::Register *thisRegister = thisRegisterForFrame(frame);
1247         return thisRegister->jsValue();
1248     }
1249 }
1250 
thisRegisterForFrame(JSC::ExecState * frame)1251 JSC::Register* QScriptEnginePrivate::thisRegisterForFrame(JSC::ExecState *frame)
1252 {
1253     Q_ASSERT(frame->codeBlock() == 0); // only for native calls
1254     return frame->registers() - JSC::RegisterFile::CallFrameHeaderSize - frame->argumentCount();
1255 }
1256 
1257 /*! \internal
1258      For native context, we use the ReturnValueRegister entry in the stackframe header to store flags.
1259      We can do that because this header is not used as the native function return their value thought C++
1260 
1261      when setting flags, NativeContext should always be set
1262 
1263      contextFlags returns 0 for non native context
1264  */
contextFlags(JSC::ExecState * exec)1265 uint QScriptEnginePrivate::contextFlags(JSC::ExecState *exec)
1266 {
1267     if (exec->codeBlock())
1268         return 0; //js function doesn't have flags
1269 
1270     return exec->returnValueRegister();
1271 }
1272 
setContextFlags(JSC::ExecState * exec,uint flags)1273 void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags)
1274 {
1275     Q_ASSERT(!exec->codeBlock());
1276     exec->registers()[JSC::RegisterFile::ReturnValueRegister] = JSC::Register::withInt(flags);
1277 }
1278 
1279 
1280 // This function is called by JSC after all objects reachable by JSC itself
1281 // have been processed (see JSC::Heap::markRoots()).
1282 // Here we should mark additional objects managed by Qt Script.
mark(JSC::MarkStack & markStack)1283 void QScriptEnginePrivate::mark(JSC::MarkStack& markStack)
1284 {
1285     Q_Q(QScriptEngine);
1286 
1287     if (originalGlobalObject()) {
1288         markStack.append(originalGlobalObject());
1289         markStack.append(globalObject());
1290         if (originalGlobalObjectProxy)
1291             markStack.append(originalGlobalObjectProxy);
1292     }
1293 
1294     if (qobjectPrototype)
1295         markStack.append(qobjectPrototype);
1296     if (qmetaobjectPrototype)
1297         markStack.append(qmetaobjectPrototype);
1298     if (variantPrototype)
1299         markStack.append(variantPrototype);
1300 
1301     {
1302         QScriptValuePrivate *it;
1303         for (it = registeredScriptValues; it != 0; it = it->next) {
1304             if (it->isJSC())
1305                 markStack.append(it->jscValue);
1306         }
1307     }
1308 
1309     {
1310         QHash<int, QScriptTypeInfo*>::const_iterator it;
1311         for (it = m_typeInfos.constBegin(); it != m_typeInfos.constEnd(); ++it) {
1312             if ((*it)->prototype)
1313                 markStack.append((*it)->prototype);
1314         }
1315     }
1316 
1317     if (q) {
1318         QScriptContext *context = q->currentContext();
1319 
1320         while (context) {
1321             JSC::ScopeChainNode *node = frameForContext(context)->scopeChain();
1322             JSC::ScopeChainIterator it(node);
1323             for (it = node->begin(); it != node->end(); ++it) {
1324                 JSC::JSObject *object = *it;
1325                 if (object)
1326                     markStack.append(object);
1327             }
1328 
1329             context = context->parentContext();
1330         }
1331     }
1332 
1333 #ifndef QT_NO_QOBJECT
1334     markQObjectData(markStack);
1335 #endif
1336 }
1337 
isCollecting() const1338 bool QScriptEnginePrivate::isCollecting() const
1339 {
1340     return globalData->heap.isBusy();
1341 }
1342 
collectGarbage()1343 void QScriptEnginePrivate::collectGarbage()
1344 {
1345     QScript::APIShim shim(this);
1346     globalData->heap.collectAllGarbage();
1347 }
1348 
reportAdditionalMemoryCost(int size)1349 void QScriptEnginePrivate::reportAdditionalMemoryCost(int size)
1350 {
1351     if (size > 0) {
1352         QScript::APIShim shim(this);
1353         globalData->heap.reportExtraMemoryCost(size);
1354     }
1355 }
1356 
timeoutChecker() const1357 QScript::TimeoutCheckerProxy *QScriptEnginePrivate::timeoutChecker() const
1358 {
1359     return static_cast<QScript::TimeoutCheckerProxy*>(globalData->timeoutChecker);
1360 }
1361 
agentDeleted(QScriptEngineAgent * agent)1362 void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent)
1363 {
1364     ownedAgents.removeOne(agent);
1365     if (activeAgent == agent) {
1366         QScriptEngineAgentPrivate::get(agent)->detach();
1367         activeAgent = 0;
1368     }
1369 }
1370 
evaluateHelper(JSC::ExecState * exec,intptr_t sourceId,JSC::EvalExecutable * executable,bool & compile)1371 JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId,
1372                                                   JSC::EvalExecutable *executable,
1373                                                   bool &compile)
1374 {
1375     Q_Q(QScriptEngine);
1376     QBoolBlocker inEvalBlocker(inEval, true);
1377     q->currentContext()->activationObject(); //force the creation of a context for native function;
1378 
1379     JSC::Debugger* debugger = originalGlobalObject()->debugger();
1380     if (debugger)
1381         debugger->evaluateStart(sourceId);
1382 
1383     q->clearExceptions();
1384     JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject);
1385 
1386     if (compile && !executable->isCompiled()) {
1387         JSC::JSObject* error = executable->compile(exec, exec->scopeChain());
1388         if (error) {
1389             compile = false;
1390             exec->setException(error);
1391 
1392             if (debugger) {
1393                 debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false);
1394                 debugger->evaluateStop(error, sourceId);
1395             }
1396 
1397             return error;
1398         }
1399     }
1400 
1401     JSC::JSValue thisValue = thisForContext(exec);
1402     JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull())
1403                                 ? exec->dynamicGlobalObject() : thisValue.toObject(exec);
1404     JSC::JSValue exceptionValue;
1405     timeoutChecker()->setShouldAbort(false);
1406     if (processEventsInterval > 0)
1407         timeoutChecker()->reset();
1408 
1409     JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue);
1410 
1411     if (timeoutChecker()->shouldAbort()) {
1412         if (abortResult.isError())
1413             exec->setException(scriptValueToJSCValue(abortResult));
1414 
1415         if (debugger)
1416             debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId);
1417 
1418         return scriptValueToJSCValue(abortResult);
1419     }
1420 
1421     if (exceptionValue) {
1422         exec->setException(exceptionValue);
1423 
1424         if (debugger)
1425             debugger->evaluateStop(exceptionValue, sourceId);
1426 
1427         return exceptionValue;
1428     }
1429 
1430     if (debugger)
1431         debugger->evaluateStop(result, sourceId);
1432 
1433     Q_ASSERT(!exec->hadException());
1434     return result;
1435 }
1436 
1437 // See ExceptionHelpers.cpp createStackOverflowError()
isLikelyStackOverflowError(JSC::ExecState * exec,JSC::JSValue value)1438 bool QScriptEnginePrivate::isLikelyStackOverflowError(JSC::ExecState *exec, JSC::JSValue value)
1439 {
1440     if (!isError(value))
1441         return false;
1442 
1443     JSC::JSValue name = property(exec, value, exec->propertyNames().name);
1444     if (!name || !name.isString() || name.toString(exec) != "RangeError")
1445         return false;
1446 
1447     JSC::JSValue message = property(exec, value, exec->propertyNames().message);
1448     if (!message || !message.isString() || message.toString(exec) != "Maximum call stack size exceeded.")
1449         return false;
1450 
1451     return true;
1452 }
1453 
1454 /*!
1455   \internal
1456   Called by the VM when an uncaught exception is being processed.
1457   If the VM call stack contains a native call inbetween two JS calls at the
1458   time the exception is thrown, this function will get called multiple times
1459   for a single exception (once per "interval" of JS call frames). In other
1460   words, at the time of this call, the VM stack can be in a partially unwound
1461   state.
1462 */
uncaughtException(JSC::ExecState * exec,unsigned bytecodeOffset,JSC::JSValue value)1463 void QScriptEnginePrivate::uncaughtException(JSC::ExecState *exec, unsigned bytecodeOffset,
1464                                              JSC::JSValue value)
1465 {
1466     // Don't capture exception information if we already have.
1467     if (uncaughtExceptionLineNumber != -1)
1468         return;
1469 
1470     QScript::SaveFrameHelper saveFrame(this, exec);
1471 
1472     uncaughtExceptionLineNumber = exec->codeBlock()->lineNumberForBytecodeOffset(exec, bytecodeOffset);
1473 
1474     if (isLikelyStackOverflowError(exec, value)) {
1475         // Don't save the backtrace, it's likely to take forever to create.
1476         uncaughtExceptionBacktrace.clear();
1477     } else {
1478         uncaughtExceptionBacktrace = contextForFrame(exec)->backtrace();
1479     }
1480 }
1481 
1482 #ifndef QT_NO_QOBJECT
1483 
markQObjectData(JSC::MarkStack & markStack)1484 void QScriptEnginePrivate::markQObjectData(JSC::MarkStack& markStack)
1485 {
1486     QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1487     // 1. Clear connection mark bits for all objects
1488     for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1489         QScript::QObjectData *qdata = it.value();
1490         qdata->clearConnectionMarkBits();
1491     }
1492 
1493     // 2. Iterate until no more connections are marked
1494     int markedCount;
1495     do {
1496         // Drain the stack to ensure mark bits are set; this is used to determine
1497         // whether a connection's sender object is weakly referenced
1498         markStack.drain();
1499 
1500         markedCount = 0;
1501         for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1502             QScript::QObjectData *qdata = it.value();
1503             markedCount += qdata->markConnections(markStack);
1504         }
1505     } while (markedCount > 0);
1506     markStack.drain(); // One last time before marking wrappers
1507 
1508     // 3. Mark all wrappers
1509     for (it = m_qobjectData.constBegin(); it != m_qobjectData.constEnd(); ++it) {
1510         QScript::QObjectData *qdata = it.value();
1511         qdata->markWrappers(markStack);
1512     }
1513 }
1514 
newQObject(QObject * object,QScriptEngine::ValueOwnership ownership,const QScriptEngine::QObjectWrapOptions & options)1515 JSC::JSValue QScriptEnginePrivate::newQObject(
1516     QObject *object, QScriptEngine::ValueOwnership ownership,
1517     const QScriptEngine::QObjectWrapOptions &options)
1518 {
1519     if (!object)
1520         return JSC::jsNull();
1521     JSC::ExecState* exec = currentFrame;
1522     QScript::QObjectData *data = qobjectData(object);
1523     bool preferExisting = (options & QScriptEngine::PreferExistingWrapperObject) != 0;
1524     QScriptEngine::QObjectWrapOptions opt = options & ~QScriptEngine::PreferExistingWrapperObject;
1525     QScriptObject *result = 0;
1526     if (preferExisting) {
1527         result = data->findWrapper(ownership, opt);
1528         if (result)
1529             return result;
1530     }
1531     result = new (exec) QScriptObject(qobjectWrapperObjectStructure);
1532     if (preferExisting)
1533         data->registerWrapper(result, ownership, opt);
1534     result->setDelegate(new QScript::QObjectDelegate(object, ownership, options));
1535     /*if (setDefaultPrototype)*/ {
1536         const QMetaObject *meta = object->metaObject();
1537         while (meta) {
1538             QByteArray typeString = meta->className();
1539             typeString.append('*');
1540             int typeId = QMetaType::type(typeString);
1541             if (typeId != 0) {
1542                 JSC::JSValue proto = defaultPrototype(typeId);
1543                 if (proto) {
1544                     result->setPrototype(proto);
1545                     break;
1546                 }
1547             }
1548             meta = meta->superClass();
1549         }
1550     }
1551     return result;
1552 }
1553 
newQMetaObject(const QMetaObject * metaObject,JSC::JSValue ctor)1554 JSC::JSValue QScriptEnginePrivate::newQMetaObject(
1555     const QMetaObject *metaObject, JSC::JSValue ctor)
1556 {
1557     if (!metaObject)
1558         return JSC::jsNull();
1559     JSC::ExecState* exec = currentFrame;
1560     QScript::QMetaObjectWrapperObject *result = new (exec) QScript::QMetaObjectWrapperObject(exec, metaObject, ctor, qmetaobjectWrapperObjectStructure);
1561     return result;
1562 }
1563 
convertToNativeQObject(JSC::ExecState * exec,JSC::JSValue value,const QByteArray & targetType,void ** result)1564 bool QScriptEnginePrivate::convertToNativeQObject(JSC::ExecState *exec, JSC::JSValue value,
1565                                                   const QByteArray &targetType,
1566                                                   void **result)
1567 {
1568     if (!targetType.endsWith('*'))
1569         return false;
1570     if (QObject *qobject = toQObject(exec, value)) {
1571         int start = targetType.startsWith("const ") ? 6 : 0;
1572         QByteArray className = targetType.mid(start, targetType.size()-start-1);
1573         if (void *instance = qobject->qt_metacast(className)) {
1574             *result = instance;
1575             return true;
1576         }
1577     }
1578     return false;
1579 }
1580 
qobjectData(QObject * object)1581 QScript::QObjectData *QScriptEnginePrivate::qobjectData(QObject *object)
1582 {
1583     QHash<QObject*, QScript::QObjectData*>::const_iterator it;
1584     it = m_qobjectData.constFind(object);
1585     if (it != m_qobjectData.constEnd())
1586         return it.value();
1587 
1588     QScript::QObjectData *data = new QScript::QObjectData(this);
1589     m_qobjectData.insert(object, data);
1590     QObject::connect(object, SIGNAL(destroyed(QObject*)),
1591                      q_func(), SLOT(_q_objectDestroyed(QObject*)));
1592     return data;
1593 }
1594 
_q_objectDestroyed(QObject * object)1595 void QScriptEnginePrivate::_q_objectDestroyed(QObject *object)
1596 {
1597     QHash<QObject*, QScript::QObjectData*>::iterator it;
1598     it = m_qobjectData.find(object);
1599     Q_ASSERT(it != m_qobjectData.end());
1600     QScript::QObjectData *data = it.value();
1601     m_qobjectData.erase(it);
1602     delete data;
1603 }
1604 
disposeQObject(QObject * object)1605 void QScriptEnginePrivate::disposeQObject(QObject *object)
1606 {
1607     // TODO
1608 /*    if (isCollecting()) {
1609         // wait until we're done with GC before deleting it
1610         int index = m_qobjectsToBeDeleted.indexOf(object);
1611         if (index == -1)
1612             m_qobjectsToBeDeleted.append(object);
1613             } else*/ {
1614         delete object;
1615     }
1616 }
1617 
emitSignalHandlerException()1618 void QScriptEnginePrivate::emitSignalHandlerException()
1619 {
1620     Q_Q(QScriptEngine);
1621     emit q->signalHandlerException(q->uncaughtException());
1622 }
1623 
scriptConnect(QObject * sender,const char * signal,JSC::JSValue receiver,JSC::JSValue function,Qt::ConnectionType type)1624 bool QScriptEnginePrivate::scriptConnect(QObject *sender, const char *signal,
1625                                          JSC::JSValue receiver, JSC::JSValue function,
1626                                          Qt::ConnectionType type)
1627 {
1628     Q_ASSERT(sender);
1629     Q_ASSERT(signal);
1630     const QMetaObject *meta = sender->metaObject();
1631     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1632     if (index == -1)
1633         return false;
1634     return scriptConnect(sender, index, receiver, function, /*wrapper=*/JSC::JSValue(), type);
1635 }
1636 
scriptDisconnect(QObject * sender,const char * signal,JSC::JSValue receiver,JSC::JSValue function)1637 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, const char *signal,
1638                                             JSC::JSValue receiver, JSC::JSValue function)
1639 {
1640     Q_ASSERT(sender);
1641     Q_ASSERT(signal);
1642     const QMetaObject *meta = sender->metaObject();
1643     int index = meta->indexOfSignal(QMetaObject::normalizedSignature(signal+1));
1644     if (index == -1)
1645         return false;
1646     return scriptDisconnect(sender, index, receiver, function);
1647 }
1648 
scriptConnect(QObject * sender,int signalIndex,JSC::JSValue receiver,JSC::JSValue function,JSC::JSValue senderWrapper,Qt::ConnectionType type)1649 bool QScriptEnginePrivate::scriptConnect(QObject *sender, int signalIndex,
1650                                          JSC::JSValue receiver, JSC::JSValue function,
1651                                          JSC::JSValue senderWrapper,
1652                                          Qt::ConnectionType type)
1653 {
1654     QScript::QObjectData *data = qobjectData(sender);
1655     return data->addSignalHandler(sender, signalIndex, receiver, function, senderWrapper, type);
1656 }
1657 
scriptDisconnect(QObject * sender,int signalIndex,JSC::JSValue receiver,JSC::JSValue function)1658 bool QScriptEnginePrivate::scriptDisconnect(QObject *sender, int signalIndex,
1659                                             JSC::JSValue receiver, JSC::JSValue function)
1660 {
1661     QScript::QObjectData *data = qobjectData(sender);
1662     if (!data)
1663         return false;
1664     return data->removeSignalHandler(sender, signalIndex, receiver, function);
1665 }
1666 
scriptConnect(JSC::JSValue signal,JSC::JSValue receiver,JSC::JSValue function,Qt::ConnectionType type)1667 bool QScriptEnginePrivate::scriptConnect(JSC::JSValue signal, JSC::JSValue receiver,
1668                                          JSC::JSValue function, Qt::ConnectionType type)
1669 {
1670     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1671     int index = fun->mostGeneralMethod();
1672     return scriptConnect(fun->qobject(), index, receiver, function, fun->wrapperObject(), type);
1673 }
1674 
scriptDisconnect(JSC::JSValue signal,JSC::JSValue receiver,JSC::JSValue function)1675 bool QScriptEnginePrivate::scriptDisconnect(JSC::JSValue signal, JSC::JSValue receiver,
1676                                             JSC::JSValue function)
1677 {
1678     QScript::QtFunction *fun = static_cast<QScript::QtFunction*>(JSC::asObject(signal));
1679     int index = fun->mostGeneralMethod();
1680     return scriptDisconnect(fun->qobject(), index, receiver, function);
1681 }
1682 
1683 #endif
1684 
detachAllRegisteredScriptPrograms()1685 void QScriptEnginePrivate::detachAllRegisteredScriptPrograms()
1686 {
1687     QSet<QScriptProgramPrivate*>::const_iterator it;
1688     for (it = registeredScriptPrograms.constBegin(); it != registeredScriptPrograms.constEnd(); ++it)
1689         (*it)->detachFromEngine();
1690     registeredScriptPrograms.clear();
1691 }
1692 
detachAllRegisteredScriptValues()1693 void QScriptEnginePrivate::detachAllRegisteredScriptValues()
1694 {
1695     QScriptValuePrivate *it;
1696     QScriptValuePrivate *next;
1697     for (it = registeredScriptValues; it != 0; it = next) {
1698         it->detachFromEngine();
1699         next = it->next;
1700         it->prev = 0;
1701         it->next = 0;
1702     }
1703     registeredScriptValues = 0;
1704 }
1705 
detachAllRegisteredScriptStrings()1706 void QScriptEnginePrivate::detachAllRegisteredScriptStrings()
1707 {
1708     QScriptStringPrivate *it;
1709     QScriptStringPrivate *next;
1710     for (it = registeredScriptStrings; it != 0; it = next) {
1711         it->detachFromEngine();
1712         next = it->next;
1713         it->prev = 0;
1714         it->next = 0;
1715     }
1716     registeredScriptStrings = 0;
1717 }
1718 
1719 #ifndef QT_NO_REGEXP
1720 
1721 Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
1722 
newRegExp(JSC::ExecState * exec,const QRegExp & regexp)1723 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QRegExp &regexp)
1724 {
1725     JSC::JSValue buf[2];
1726     JSC::ArgList args(buf, sizeof(buf));
1727 
1728     //convert the pattern to a ECMAScript pattern
1729     QString pattern = qt_regexp_toCanonical(regexp.pattern(), regexp.patternSyntax());
1730     if (regexp.isMinimal()) {
1731         QString ecmaPattern;
1732         int len = pattern.length();
1733         ecmaPattern.reserve(len);
1734         int i = 0;
1735         const QChar *wc = pattern.unicode();
1736         bool inBracket = false;
1737         while (i < len) {
1738             QChar c = wc[i++];
1739             ecmaPattern += c;
1740             switch (c.unicode()) {
1741             case '?':
1742             case '+':
1743             case '*':
1744             case '}':
1745                 if (!inBracket)
1746                     ecmaPattern += QLatin1Char('?');
1747                 break;
1748             case '\\':
1749                 if (i < len)
1750                     ecmaPattern += wc[i++];
1751                 break;
1752             case '[':
1753                 inBracket = true;
1754                 break;
1755             case ']':
1756                 inBracket = false;
1757                break;
1758             default:
1759                 break;
1760             }
1761         }
1762         pattern = ecmaPattern;
1763     }
1764 
1765     JSC::UString jscPattern = pattern;
1766     QString flags;
1767     if (regexp.caseSensitivity() == Qt::CaseInsensitive)
1768         flags.append(QLatin1Char('i'));
1769     JSC::UString jscFlags = flags;
1770     buf[0] = JSC::jsString(exec, jscPattern);
1771     buf[1] = JSC::jsString(exec, jscFlags);
1772     return JSC::constructRegExp(exec, args);
1773 }
1774 
1775 #endif
1776 
newRegExp(JSC::ExecState * exec,const QString & pattern,const QString & flags)1777 JSC::JSValue QScriptEnginePrivate::newRegExp(JSC::ExecState *exec, const QString &pattern, const QString &flags)
1778 {
1779     JSC::JSValue buf[2];
1780     JSC::ArgList args(buf, sizeof(buf));
1781     JSC::UString jscPattern = pattern;
1782     QString strippedFlags;
1783     if (flags.contains(QLatin1Char('i')))
1784         strippedFlags += QLatin1Char('i');
1785     if (flags.contains(QLatin1Char('m')))
1786         strippedFlags += QLatin1Char('m');
1787     if (flags.contains(QLatin1Char('g')))
1788         strippedFlags += QLatin1Char('g');
1789     JSC::UString jscFlags = strippedFlags;
1790     buf[0] = JSC::jsString(exec, jscPattern);
1791     buf[1] = JSC::jsString(exec, jscFlags);
1792     return JSC::constructRegExp(exec, args);
1793 }
1794 
newVariant(const QVariant & value)1795 JSC::JSValue QScriptEnginePrivate::newVariant(const QVariant &value)
1796 {
1797     QScriptObject *obj = new (currentFrame) QScriptObject(variantWrapperObjectStructure);
1798     obj->setDelegate(new QScript::QVariantDelegate(value));
1799     JSC::JSValue proto = defaultPrototype(value.userType());
1800     if (proto)
1801         obj->setPrototype(proto);
1802     return obj;
1803 }
1804 
newVariant(JSC::JSValue objectValue,const QVariant & value)1805 JSC::JSValue QScriptEnginePrivate::newVariant(JSC::JSValue objectValue,
1806                                               const QVariant &value)
1807 {
1808     if (!isObject(objectValue))
1809         return newVariant(value);
1810     JSC::JSObject *jscObject = JSC::asObject(objectValue);
1811     if (!jscObject->inherits(&QScriptObject::info)) {
1812         qWarning("QScriptEngine::newVariant(): changing class of non-QScriptObject not supported");
1813         return JSC::JSValue();
1814     }
1815     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
1816     if (!isVariant(objectValue)) {
1817         jscScriptObject->setDelegate(new QScript::QVariantDelegate(value));
1818     } else {
1819         setVariantValue(objectValue, value);
1820     }
1821     return objectValue;
1822 }
1823 
1824 #ifndef QT_NO_REGEXP
1825 
toRegExp(JSC::ExecState * exec,JSC::JSValue value)1826 QRegExp QScriptEnginePrivate::toRegExp(JSC::ExecState *exec, JSC::JSValue value)
1827 {
1828     if (!isRegExp(value))
1829         return QRegExp();
1830     QString pattern = toString(exec, property(exec, value, "source", QScriptValue::ResolvePrototype));
1831     Qt::CaseSensitivity kase = Qt::CaseSensitive;
1832     if (toBool(exec, property(exec, value, "ignoreCase", QScriptValue::ResolvePrototype)))
1833         kase = Qt::CaseInsensitive;
1834     return QRegExp(pattern, kase, QRegExp::RegExp2);
1835 }
1836 
1837 #endif
1838 
toVariant(JSC::ExecState * exec,JSC::JSValue value)1839 QVariant QScriptEnginePrivate::toVariant(JSC::ExecState *exec, JSC::JSValue value)
1840 {
1841     if (!value) {
1842         return QVariant();
1843     } else if (isObject(value)) {
1844         if (isVariant(value))
1845             return variantValue(value);
1846 #ifndef QT_NO_QOBJECT
1847         else if (isQObject(value))
1848             return QVariant::fromValue(toQObject(exec, value));
1849 #endif
1850         else if (isDate(value))
1851             return QVariant(toDateTime(exec, value));
1852 #ifndef QT_NO_REGEXP
1853         else if (isRegExp(value))
1854             return QVariant(toRegExp(exec, value));
1855 #endif
1856         else if (isArray(value))
1857             return variantListFromArray(exec, JSC::asArray(value));
1858         else if (QScriptDeclarativeClass *dc = declarativeClass(value))
1859             return dc->toVariant(declarativeObject(value));
1860         return variantMapFromObject(exec, JSC::asObject(value));
1861     } else if (value.isInt32()) {
1862         return QVariant(toInt32(exec, value));
1863     } else if (value.isDouble()) {
1864         return QVariant(toNumber(exec, value));
1865     } else if (value.isString()) {
1866         return QVariant(toString(exec, value));
1867     } else if (value.isBoolean()) {
1868         return QVariant(toBool(exec, value));
1869     }
1870     return QVariant();
1871 }
1872 
propertyHelper(JSC::ExecState * exec,JSC::JSValue value,const JSC::Identifier & id,int resolveMode)1873 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id, int resolveMode)
1874 {
1875     JSC::JSValue result;
1876     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1877         // Look in the object's own properties
1878         JSC::JSObject *object = JSC::asObject(value);
1879         JSC::PropertySlot slot(object);
1880         if (object->getOwnPropertySlot(exec, id, slot))
1881             result = slot.getValue(exec, id);
1882     }
1883     if (!result && (resolveMode & QScriptValue::ResolveScope)) {
1884         // ### check if it's a function object and look in the scope chain
1885         JSC::JSValue scope = property(exec, value, "__qt_scope__", QScriptValue::ResolveLocal);
1886         if (isObject(scope))
1887             result = property(exec, scope, id, resolveMode);
1888     }
1889     return result;
1890 }
1891 
propertyHelper(JSC::ExecState * exec,JSC::JSValue value,quint32 index,int resolveMode)1892 JSC::JSValue QScriptEnginePrivate::propertyHelper(JSC::ExecState *exec, JSC::JSValue value, quint32 index, int resolveMode)
1893 {
1894     JSC::JSValue result;
1895     if (!(resolveMode & QScriptValue::ResolvePrototype)) {
1896         // Look in the object's own properties
1897         JSC::JSObject *object = JSC::asObject(value);
1898         JSC::PropertySlot slot(object);
1899         if (object->getOwnPropertySlot(exec, index, slot))
1900             result = slot.getValue(exec, index);
1901     }
1902     return result;
1903 }
1904 
setProperty(JSC::ExecState * exec,JSC::JSValue objectValue,const JSC::Identifier & id,JSC::JSValue value,const QScriptValue::PropertyFlags & flags)1905 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, const JSC::Identifier &id,
1906                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1907 {
1908     JSC::JSObject *thisObject = JSC::asObject(objectValue);
1909     JSC::JSValue setter = thisObject->lookupSetter(exec, id);
1910     JSC::JSValue getter = thisObject->lookupGetter(exec, id);
1911     if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1912         if (!value) {
1913             // deleting getter/setter
1914             if ((flags & QScriptValue::PropertyGetter) && (flags & QScriptValue::PropertySetter)) {
1915                 // deleting both: just delete the property
1916                 thisObject->deleteProperty(exec, id);
1917             } else if (flags & QScriptValue::PropertyGetter) {
1918                 // preserve setter, if there is one
1919                 thisObject->deleteProperty(exec, id);
1920                 if (setter && setter.isObject())
1921                     thisObject->defineSetter(exec, id, JSC::asObject(setter));
1922             } else { // flags & QScriptValue::PropertySetter
1923                 // preserve getter, if there is one
1924                 thisObject->deleteProperty(exec, id);
1925                 if (getter && getter.isObject())
1926                     thisObject->defineGetter(exec, id, JSC::asObject(getter));
1927             }
1928         } else {
1929             if (value.isObject()) { // ### should check if it has callData()
1930                 // defining getter/setter
1931                 if (id == exec->propertyNames().underscoreProto) {
1932                     qWarning("QScriptValue::setProperty() failed: "
1933                              "cannot set getter or setter of native property `__proto__'");
1934                 } else {
1935                     if (flags & QScriptValue::PropertyGetter)
1936                         thisObject->defineGetter(exec, id, JSC::asObject(value));
1937                     if (flags & QScriptValue::PropertySetter)
1938                         thisObject->defineSetter(exec, id, JSC::asObject(value));
1939                 }
1940             } else {
1941                 qWarning("QScriptValue::setProperty(): getter/setter must be a function");
1942             }
1943         }
1944     } else {
1945         // setting the value
1946         if (getter && getter.isObject() && !(setter && setter.isObject())) {
1947             qWarning("QScriptValue::setProperty() failed: "
1948                      "property '%s' has a getter but no setter",
1949                      qPrintable(QString(id.ustring())));
1950             return;
1951         }
1952         if (!value) {
1953             // ### check if it's a getter/setter property
1954             thisObject->deleteProperty(exec, id);
1955         } else if (flags != QScriptValue::KeepExistingFlags) {
1956             if (thisObject->hasOwnProperty(exec, id))
1957                 thisObject->deleteProperty(exec, id); // ### hmmm - can't we just update the attributes?
1958             thisObject->putWithAttributes(exec, id, value, propertyFlagsToJSCAttributes(flags));
1959         } else {
1960             JSC::PutPropertySlot slot;
1961             thisObject->put(exec, id, value, slot);
1962         }
1963     }
1964 }
1965 
setProperty(JSC::ExecState * exec,JSC::JSValue objectValue,quint32 index,JSC::JSValue value,const QScriptValue::PropertyFlags & flags)1966 void QScriptEnginePrivate::setProperty(JSC::ExecState *exec, JSC::JSValue objectValue, quint32 index,
1967                                        JSC::JSValue value, const QScriptValue::PropertyFlags &flags)
1968 {
1969     if (!value) {
1970         JSC::asObject(objectValue)->deleteProperty(exec, index);
1971     } else {
1972         if ((flags & QScriptValue::PropertyGetter) || (flags & QScriptValue::PropertySetter)) {
1973             // fall back to string-based setProperty(), since there is no
1974             // JSC::JSObject::defineGetter(unsigned)
1975             setProperty(exec, objectValue, JSC::Identifier::from(exec, index), value, flags);
1976         } else {
1977             if (flags != QScriptValue::KeepExistingFlags) {
1978                 //                if (JSC::asObject(d->jscValue)->hasOwnProperty(exec, arrayIndex))
1979                 //                    JSC::asObject(d->jscValue)->deleteProperty(exec, arrayIndex);
1980                 unsigned attribs = 0;
1981                 if (flags & QScriptValue::ReadOnly)
1982                     attribs |= JSC::ReadOnly;
1983                 if (flags & QScriptValue::SkipInEnumeration)
1984                     attribs |= JSC::DontEnum;
1985                 if (flags & QScriptValue::Undeletable)
1986                     attribs |= JSC::DontDelete;
1987                 attribs |= flags & QScriptValue::UserRange;
1988                 JSC::asObject(objectValue)->putWithAttributes(exec, index, value, attribs);
1989             } else {
1990                 JSC::asObject(objectValue)->put(exec, index, value);
1991             }
1992         }
1993     }
1994 }
1995 
propertyFlags(JSC::ExecState * exec,JSC::JSValue value,const JSC::Identifier & id,const QScriptValue::ResolveFlags & mode)1996 QScriptValue::PropertyFlags QScriptEnginePrivate::propertyFlags(JSC::ExecState *exec, JSC::JSValue value, const JSC::Identifier &id,
1997                                                                 const QScriptValue::ResolveFlags &mode)
1998 {
1999     JSC::JSObject *object = JSC::asObject(value);
2000     unsigned attribs = 0;
2001     JSC::PropertyDescriptor descriptor;
2002     if (object->getOwnPropertyDescriptor(exec, id, descriptor))
2003         attribs = descriptor.attributes();
2004     else {
2005         if ((mode & QScriptValue::ResolvePrototype) && object->prototype() && object->prototype().isObject()) {
2006             JSC::JSValue proto = object->prototype();
2007             return propertyFlags(exec, proto, id, mode);
2008         }
2009         return {};
2010     }
2011     QScriptValue::PropertyFlags result;
2012     if (attribs & JSC::ReadOnly)
2013         result |= QScriptValue::ReadOnly;
2014     if (attribs & JSC::DontEnum)
2015         result |= QScriptValue::SkipInEnumeration;
2016     if (attribs & JSC::DontDelete)
2017         result |= QScriptValue::Undeletable;
2018     //We cannot rely on attribs JSC::Setter/Getter because they are not necesserly set by JSC (bug?)
2019     if (attribs & JSC::Getter || !object->lookupGetter(exec, id).isUndefinedOrNull())
2020         result |= QScriptValue::PropertyGetter;
2021     if (attribs & JSC::Setter || !object->lookupSetter(exec, id).isUndefinedOrNull())
2022         result |= QScriptValue::PropertySetter;
2023 #ifndef QT_NO_QOBJECT
2024     if (attribs & QScript::QObjectMemberAttribute)
2025         result |= QScriptValue::QObjectMember;
2026 #endif
2027     result |= QScriptValue::PropertyFlag(attribs & QScriptValue::UserRange);
2028     return result;
2029 }
2030 
toStringHandle(const JSC::Identifier & name)2031 QScriptString QScriptEnginePrivate::toStringHandle(const JSC::Identifier &name)
2032 {
2033     QScriptString result;
2034     QScriptStringPrivate *p = new QScriptStringPrivate(this, name, QScriptStringPrivate::HeapAllocated);
2035     QScriptStringPrivate::init(result, p);
2036     registerScriptString(p);
2037     return result;
2038 }
2039 
2040 #ifdef QT_NO_QOBJECT
2041 
QScriptEngine()2042 QScriptEngine::QScriptEngine()
2043     : d_ptr(new QScriptEnginePrivate)
2044 {
2045     d_ptr->q_ptr = this;
2046 }
2047 
2048 /*! \internal
2049 */
QScriptEngine(QScriptEnginePrivate & dd)2050 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd)
2051     : d_ptr(&dd)
2052 {
2053     d_ptr->q_ptr = this;
2054 }
2055 #else
2056 
2057 /*!
2058     Constructs a QScriptEngine object.
2059 
2060     The globalObject() is initialized to have properties as described in
2061     \l{ECMA-262}, Section 15.1.
2062 */
QScriptEngine()2063 QScriptEngine::QScriptEngine()
2064     : QObject(*new QScriptEnginePrivate, 0)
2065 {
2066 }
2067 
2068 /*!
2069     Constructs a QScriptEngine object with the given \a parent.
2070 
2071     The globalObject() is initialized to have properties as described in
2072     \l{ECMA-262}, Section 15.1.
2073 */
2074 
QScriptEngine(QObject * parent)2075 QScriptEngine::QScriptEngine(QObject *parent)
2076     : QObject(*new QScriptEnginePrivate, parent)
2077 {
2078 }
2079 
2080 /*! \internal
2081 */
QScriptEngine(QScriptEnginePrivate & dd,QObject * parent)2082 QScriptEngine::QScriptEngine(QScriptEnginePrivate &dd, QObject *parent)
2083     : QObject(dd, parent)
2084 {
2085 }
2086 #endif
2087 
2088 /*!
2089   Destroys this QScriptEngine.
2090 */
~QScriptEngine()2091 QScriptEngine::~QScriptEngine()
2092 {
2093 #ifdef QT_NO_QOBJECT
2094     delete d_ptr;
2095     d_ptr = 0;
2096 #endif
2097 }
2098 
2099 /*!
2100   Returns this engine's Global Object.
2101 
2102   By default, the Global Object contains the built-in objects that are
2103   part of \l{ECMA-262}, such as Math, Date and String. Additionally,
2104   you can set properties of the Global Object to make your own
2105   extensions available to all script code. Non-local variables in
2106   script code will be created as properties of the Global Object, as
2107   well as local variables in global code.
2108 */
globalObject() const2109 QScriptValue QScriptEngine::globalObject() const
2110 {
2111     Q_D(const QScriptEngine);
2112     QScript::APIShim shim(const_cast<QScriptEnginePrivate*>(d));
2113     JSC::JSObject *result = d->globalObject();
2114     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(result);
2115 }
2116 
2117 /*!
2118   \since 4.5
2119 
2120   Sets this engine's Global Object to be the given \a object.
2121   If \a object is not a valid script object, this function does
2122   nothing.
2123 
2124   When setting a custom global object, you may want to use
2125   QScriptValueIterator to copy the properties of the standard Global
2126   Object; alternatively, you can set the internal prototype of your
2127   custom object to be the original Global Object.
2128 */
setGlobalObject(const QScriptValue & object)2129 void QScriptEngine::setGlobalObject(const QScriptValue &object)
2130 {
2131     Q_D(QScriptEngine);
2132     if (!object.isObject())
2133         return;
2134     QScript::APIShim shim(d);
2135     JSC::JSObject *jscObject = JSC::asObject(d->scriptValueToJSCValue(object));
2136     d->setGlobalObject(jscObject);
2137 }
2138 
2139 /*!
2140   Returns a QScriptValue of the primitive type Null.
2141 
2142   \sa undefinedValue()
2143 */
nullValue()2144 QScriptValue QScriptEngine::nullValue()
2145 {
2146     Q_D(QScriptEngine);
2147     return d->scriptValueFromJSCValue(JSC::jsNull());
2148 }
2149 
2150 /*!
2151   Returns a QScriptValue of the primitive type Undefined.
2152 
2153   \sa nullValue()
2154 */
undefinedValue()2155 QScriptValue QScriptEngine::undefinedValue()
2156 {
2157     Q_D(QScriptEngine);
2158     return d->scriptValueFromJSCValue(JSC::jsUndefined());
2159 }
2160 
2161 /*!
2162   Creates a constructor function from \a fun, with the given \a length.
2163   The \c{prototype} property of the resulting function is set to be the
2164   given \a prototype. The \c{constructor} property of \a prototype is
2165   set to be the resulting function.
2166 
2167   When a function is called as a constructor (e.g. \c{new Foo()}), the
2168   `this' object associated with the function call is the new object
2169   that the function is expected to initialize; the prototype of this
2170   default constructed object will be the function's public
2171   \c{prototype} property. If you always want the function to behave as
2172   a constructor (e.g. \c{Foo()} should also create a new object), or
2173   if you need to create your own object rather than using the default
2174   `this' object, you should make sure that the prototype of your
2175   object is set correctly; either by setting it manually, or, when
2176   wrapping a custom type, by having registered the defaultPrototype()
2177   of that type. Example:
2178 
2179   \snippet code/src_script_qscriptengine.cpp 9
2180 
2181   To wrap a custom type and provide a constructor for it, you'd typically
2182   do something like this:
2183 
2184   \snippet code/src_script_qscriptengine.cpp 10
2185 */
newFunction(QScriptEngine::FunctionSignature fun,const QScriptValue & prototype,int length)2186 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun,
2187                                         const QScriptValue &prototype,
2188                                         int length)
2189 {
2190     Q_D(QScriptEngine);
2191     QScript::APIShim shim(d);
2192     JSC::ExecState* exec = d->currentFrame;
2193     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2194     QScriptValue result = d->scriptValueFromJSCValue(function);
2195     result.setProperty(QLatin1String("prototype"), prototype,
2196                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2197     const_cast<QScriptValue&>(prototype)
2198         .setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2199     return result;
2200 }
2201 
2202 #ifndef QT_NO_REGEXP
2203 
2204 /*!
2205   Creates a Qt Script object of class RegExp with the given
2206   \a regexp.
2207 
2208   \sa QScriptValue::toRegExp()
2209 */
newRegExp(const QRegExp & regexp)2210 QScriptValue QScriptEngine::newRegExp(const QRegExp &regexp)
2211 {
2212     Q_D(QScriptEngine);
2213     QScript::APIShim shim(d);
2214     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, regexp));
2215 }
2216 
2217 #endif // QT_NO_REGEXP
2218 
2219 /*!
2220   Creates a Qt Script object holding the given variant \a value.
2221 
2222   If a default prototype has been registered with the meta type id of
2223   \a value, then the prototype of the created object will be that
2224   prototype; otherwise, the prototype will be the Object prototype
2225   object.
2226 
2227   \sa setDefaultPrototype(), QScriptValue::toVariant(), reportAdditionalMemoryCost()
2228 */
newVariant(const QVariant & value)2229 QScriptValue QScriptEngine::newVariant(const QVariant &value)
2230 {
2231     Q_D(QScriptEngine);
2232     QScript::APIShim shim(d);
2233     return d->scriptValueFromJSCValue(d->newVariant(value));
2234 }
2235 
2236 /*!
2237   \since 4.4
2238   \overload
2239 
2240   Initializes the given Qt Script \a object to hold the given variant
2241   \a value, and returns the \a object.
2242 
2243   This function enables you to "promote" a plain Qt Script object
2244   (created by the newObject() function) to a variant, or to replace
2245   the variant contained inside an object previously created by the
2246   newVariant() function.
2247 
2248   The prototype() of the \a object will remain unchanged.
2249 
2250   If \a object is not an object, this function behaves like the normal
2251   newVariant(), i.e. it creates a new script object and returns it.
2252 
2253   This function is useful when you want to provide a script
2254   constructor for a C++ type. If your constructor is invoked in a
2255   \c{new} expression (QScriptContext::isCalledAsConstructor() returns
2256   true), you can pass QScriptContext::thisObject() (the default
2257   constructed script object) to this function to initialize the new
2258   object.
2259 
2260   \sa reportAdditionalMemoryCost()
2261 */
newVariant(const QScriptValue & object,const QVariant & value)2262 QScriptValue QScriptEngine::newVariant(const QScriptValue &object,
2263                                        const QVariant &value)
2264 {
2265     Q_D(QScriptEngine);
2266     QScript::APIShim shim(d);
2267     JSC::JSValue jsObject = d->scriptValueToJSCValue(object);
2268     return d->scriptValueFromJSCValue(d->newVariant(jsObject, value));
2269 }
2270 
2271 #ifndef QT_NO_QOBJECT
2272 /*!
2273   Creates a Qt Script object that wraps the given QObject \a
2274   object, using the given \a ownership. The given \a options control
2275   various aspects of the interaction with the resulting script object.
2276 
2277   Signals and slots, properties and children of \a object are
2278   available as properties of the created QScriptValue. For more
2279   information, see the \l{Qt Script} documentation.
2280 
2281   If \a object is a null pointer, this function returns nullValue().
2282 
2283   If a default prototype has been registered for the \a object's class
2284   (or its superclass, recursively), the prototype of the new script
2285   object will be set to be that default prototype.
2286 
2287   If the given \a object is deleted outside of Qt Script's control, any
2288   attempt to access the deleted QObject's members through the Qt Script
2289   wrapper object (either by script code or C++) will result in a
2290   script exception.
2291 
2292   \sa QScriptValue::toQObject(), reportAdditionalMemoryCost()
2293 */
newQObject(QObject * object,ValueOwnership ownership,const QObjectWrapOptions & options)2294 QScriptValue QScriptEngine::newQObject(QObject *object, ValueOwnership ownership,
2295                                        const QObjectWrapOptions &options)
2296 {
2297     Q_D(QScriptEngine);
2298     QScript::APIShim shim(d);
2299     JSC::JSValue jscQObject = d->newQObject(object, ownership, options);
2300     return d->scriptValueFromJSCValue(jscQObject);
2301 }
2302 
2303 /*!
2304   \since 4.4
2305   \overload
2306 
2307   Initializes the given \a scriptObject to hold the given \a qtObject,
2308   and returns the \a scriptObject.
2309 
2310   This function enables you to "promote" a plain Qt Script object
2311   (created by the newObject() function) to a QObject proxy, or to
2312   replace the QObject contained inside an object previously created by
2313   the newQObject() function.
2314 
2315   The prototype() of the \a scriptObject will remain unchanged.
2316 
2317   If \a scriptObject is not an object, this function behaves like the
2318   normal newQObject(), i.e. it creates a new script object and returns
2319   it.
2320 
2321   This function is useful when you want to provide a script
2322   constructor for a QObject-based class. If your constructor is
2323   invoked in a \c{new} expression
2324   (QScriptContext::isCalledAsConstructor() returns true), you can pass
2325   QScriptContext::thisObject() (the default constructed script object)
2326   to this function to initialize the new object.
2327 
2328   \sa reportAdditionalMemoryCost()
2329 */
newQObject(const QScriptValue & scriptObject,QObject * qtObject,ValueOwnership ownership,const QObjectWrapOptions & options)2330 QScriptValue QScriptEngine::newQObject(const QScriptValue &scriptObject,
2331                                        QObject *qtObject,
2332                                        ValueOwnership ownership,
2333                                        const QObjectWrapOptions &options)
2334 {
2335     Q_D(QScriptEngine);
2336     if (!scriptObject.isObject())
2337         return newQObject(qtObject, ownership, options);
2338     QScript::APIShim shim(d);
2339     JSC::JSObject *jscObject = JSC::asObject(QScriptValuePrivate::get(scriptObject)->jscValue);
2340     if (!jscObject->inherits(&QScriptObject::info)) {
2341         qWarning("QScriptEngine::newQObject(): changing class of non-QScriptObject not supported");
2342         return QScriptValue();
2343     }
2344     QScriptObject *jscScriptObject = static_cast<QScriptObject*>(jscObject);
2345     if (!scriptObject.isQObject()) {
2346         jscScriptObject->setDelegate(new QScript::QObjectDelegate(qtObject, ownership, options));
2347     } else {
2348         QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(jscScriptObject->delegate());
2349         delegate->setValue(qtObject);
2350         delegate->setOwnership(ownership);
2351         delegate->setOptions(options);
2352     }
2353     return scriptObject;
2354 }
2355 
2356 #endif // QT_NO_QOBJECT
2357 
2358 /*!
2359   Creates a Qt Script object of class Object.
2360 
2361   The prototype of the created object will be the Object
2362   prototype object.
2363 
2364   \sa newArray(), QScriptValue::setProperty()
2365 */
newObject()2366 QScriptValue QScriptEngine::newObject()
2367 {
2368     Q_D(QScriptEngine);
2369     QScript::APIShim shim(d);
2370     return d->scriptValueFromJSCValue(d->newObject());
2371 }
2372 
2373 /*!
2374   \since 4.4
2375   \overload
2376 
2377   Creates a Qt Script Object of the given class, \a scriptClass.
2378 
2379   The prototype of the created object will be the Object
2380   prototype object.
2381 
2382   \a data, if specified, is set as the internal data of the
2383   new object (using QScriptValue::setData()).
2384 
2385   \sa QScriptValue::scriptClass(), reportAdditionalMemoryCost()
2386 */
newObject(QScriptClass * scriptClass,const QScriptValue & data)2387 QScriptValue QScriptEngine::newObject(QScriptClass *scriptClass,
2388                                       const QScriptValue &data)
2389 {
2390     Q_D(QScriptEngine);
2391     QScript::APIShim shim(d);
2392     JSC::ExecState* exec = d->currentFrame;
2393     QScriptObject *result = new (exec) QScriptObject(d->scriptObjectStructure);
2394     result->setDelegate(new QScript::ClassObjectDelegate(scriptClass));
2395     QScriptValue scriptObject = d->scriptValueFromJSCValue(result);
2396     scriptObject.setData(data);
2397     QScriptValue proto = scriptClass->prototype();
2398     if (proto.isValid())
2399         scriptObject.setPrototype(proto);
2400     return scriptObject;
2401 }
2402 
2403 /*!
2404   \internal
2405 */
newActivationObject()2406 QScriptValue QScriptEngine::newActivationObject()
2407 {
2408     qWarning("QScriptEngine::newActivationObject() not implemented");
2409     // ### JSActivation or JSVariableObject?
2410     return QScriptValue();
2411 }
2412 
2413 /*!
2414   Creates a QScriptValue that wraps a native (C++) function. \a fun
2415   must be a C++ function with signature QScriptEngine::FunctionSignature.  \a
2416   length is the number of arguments that \a fun expects; this becomes
2417   the \c{length} property of the created QScriptValue.
2418 
2419   Note that \a length only gives an indication of the number of
2420   arguments that the function expects; an actual invocation of a
2421   function can include any number of arguments. You can check the
2422   \l{QScriptContext::argumentCount()}{argumentCount()} of the
2423   QScriptContext associated with the invocation to determine the
2424   actual number of arguments passed.
2425 
2426   A \c{prototype} property is automatically created for the resulting
2427   function object, to provide for the possibility that the function
2428   will be used as a constructor.
2429 
2430   By combining newFunction() and the property flags
2431   QScriptValue::PropertyGetter and QScriptValue::PropertySetter, you
2432   can create script object properties that behave like normal
2433   properties in script code, but are in fact accessed through
2434   functions (analogous to how properties work in \l{Qt's Property
2435   System}). Example:
2436 
2437   \snippet code/src_script_qscriptengine.cpp 11
2438 
2439   When the property \c{foo} of the script object is subsequently
2440   accessed in script code, \c{getSetFoo()} will be invoked to handle
2441   the access.  In this particular case, we chose to store the "real"
2442   value of \c{foo} as a property of the accessor function itself; you
2443   are of course free to do whatever you like in this function.
2444 
2445   In the above example, a single native function was used to handle
2446   both reads and writes to the property; the argument count is used to
2447   determine if we are handling a read or write. You can also use two
2448   separate functions; just specify the relevant flag
2449   (QScriptValue::PropertyGetter or QScriptValue::PropertySetter) when
2450   setting the property, e.g.:
2451 
2452   \snippet code/src_script_qscriptengine.cpp 12
2453 
2454   \sa QScriptValue::call()
2455 */
newFunction(QScriptEngine::FunctionSignature fun,int length)2456 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionSignature fun, int length)
2457 {
2458     Q_D(QScriptEngine);
2459     QScript::APIShim shim(d);
2460     JSC::ExecState* exec = d->currentFrame;
2461     JSC::JSValue function = new (exec)QScript::FunctionWrapper(exec, length, JSC::Identifier(exec, ""), fun);
2462     QScriptValue result = d->scriptValueFromJSCValue(function);
2463     QScriptValue proto = newObject();
2464     result.setProperty(QLatin1String("prototype"), proto,
2465                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2466     proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2467     return result;
2468 }
2469 
2470 /*!
2471   \internal
2472   \since 4.4
2473 */
newFunction(QScriptEngine::FunctionWithArgSignature fun,void * arg)2474 QScriptValue QScriptEngine::newFunction(QScriptEngine::FunctionWithArgSignature fun, void *arg)
2475 {
2476     Q_D(QScriptEngine);
2477     QScript::APIShim shim(d);
2478     JSC::ExecState* exec = d->currentFrame;
2479     JSC::JSValue function = new (exec)QScript::FunctionWithArgWrapper(exec, /*length=*/0, JSC::Identifier(exec, ""), fun, arg);
2480     QScriptValue result = d->scriptValueFromJSCValue(function);
2481     QScriptValue proto = newObject();
2482     result.setProperty(QLatin1String("prototype"), proto,
2483                        QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
2484     proto.setProperty(QLatin1String("constructor"), result, QScriptValue::SkipInEnumeration);
2485     return result;
2486 }
2487 
2488 /*!
2489   Creates a Qt Script object of class Array with the given \a length.
2490 
2491   \sa newObject()
2492 */
newArray(uint length)2493 QScriptValue QScriptEngine::newArray(uint length)
2494 {
2495     Q_D(QScriptEngine);
2496     QScript::APIShim shim(d);
2497     return d->scriptValueFromJSCValue(d->newArray(d->currentFrame, length));
2498 }
2499 
2500 /*!
2501   Creates a Qt Script object of class RegExp with the given
2502   \a pattern and \a flags.
2503 
2504   The legal flags are 'g' (global), 'i' (ignore case), and 'm'
2505   (multiline).
2506 */
newRegExp(const QString & pattern,const QString & flags)2507 QScriptValue QScriptEngine::newRegExp(const QString &pattern, const QString &flags)
2508 {
2509     Q_D(QScriptEngine);
2510     QScript::APIShim shim(d);
2511     return d->scriptValueFromJSCValue(d->newRegExp(d->currentFrame, pattern, flags));
2512 }
2513 
2514 /*!
2515   Creates a Qt Script object of class Date with the given
2516   \a value (the number of milliseconds since 01 January 1970,
2517   UTC).
2518 */
newDate(qsreal value)2519 QScriptValue QScriptEngine::newDate(qsreal value)
2520 {
2521     Q_D(QScriptEngine);
2522     QScript::APIShim shim(d);
2523     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2524 }
2525 
2526 /*!
2527   Creates a Qt Script object of class Date from the given \a value.
2528 
2529   \sa QScriptValue::toDateTime()
2530 */
newDate(const QDateTime & value)2531 QScriptValue QScriptEngine::newDate(const QDateTime &value)
2532 {
2533     Q_D(QScriptEngine);
2534     QScript::APIShim shim(d);
2535     return d->scriptValueFromJSCValue(d->newDate(d->currentFrame, value));
2536 }
2537 
2538 #ifndef QT_NO_QOBJECT
2539 /*!
2540   Creates a Qt Script object that represents a QObject class, using the
2541   the given \a metaObject and constructor \a ctor.
2542 
2543   Enums of \a metaObject (declared with Q_ENUMS) are available as
2544   properties of the created QScriptValue. When the class is called as
2545   a function, \a ctor will be called to create a new instance of the
2546   class.
2547 
2548   Example:
2549 
2550   \snippet code/src_script_qscriptengine.cpp 27
2551 
2552   \sa newQObject(), scriptValueFromQMetaObject()
2553 */
newQMetaObject(const QMetaObject * metaObject,const QScriptValue & ctor)2554 QScriptValue QScriptEngine::newQMetaObject(
2555     const QMetaObject *metaObject, const QScriptValue &ctor)
2556 {
2557     Q_D(QScriptEngine);
2558     QScript::APIShim shim(d);
2559     JSC::JSValue jscCtor = d->scriptValueToJSCValue(ctor);
2560     JSC::JSValue jscQMetaObject = d->newQMetaObject(metaObject, jscCtor);
2561     return d->scriptValueFromJSCValue(jscQMetaObject);
2562 }
2563 
2564 /*!
2565   \fn QScriptValue QScriptEngine::scriptValueFromQMetaObject()
2566 
2567   Creates a QScriptValue that represents the Qt class \c{T}.
2568 
2569   This function is used in combination with one of the
2570   Q_SCRIPT_DECLARE_QMETAOBJECT() macro. Example:
2571 
2572   \snippet code/src_script_qscriptengine.cpp 13
2573 
2574   \sa QScriptEngine::newQMetaObject()
2575 */
2576 
2577 /*!
2578   \fn QScriptValue qScriptValueFromQMetaObject(QScriptEngine *engine)
2579   \since 4.3
2580   \relates QScriptEngine
2581   \obsolete
2582 
2583   Uses \a engine to create a QScriptValue that represents the Qt class
2584   \c{T}.
2585 
2586   This function is equivalent to
2587   QScriptEngine::scriptValueFromQMetaObject().
2588 
2589   \note This function was provided as a workaround for MSVC 6
2590   which did not support member template functions. It is advised
2591   to use the other form in new code.
2592 
2593   \sa QScriptEngine::newQMetaObject()
2594 */
2595 #endif // QT_NO_QOBJECT
2596 
2597 /*!
2598   \obsolete
2599 
2600   Returns true if \a program can be evaluated; i.e. the code is
2601   sufficient to determine whether it appears to be a syntactically
2602   correct program, or contains a syntax error.
2603 
2604   This function returns false if \a program is incomplete; i.e. the
2605   input is syntactically correct up to the point where the input is
2606   terminated.
2607 
2608   Note that this function only does a static check of \a program;
2609   e.g. it does not check whether references to variables are
2610   valid, and so on.
2611 
2612   A typical usage of canEvaluate() is to implement an interactive
2613   interpreter for Qt Script. The user is repeatedly queried for
2614   individual lines of code; the lines are concatened internally, and
2615   only when canEvaluate() returns true for the resulting program is it
2616   passed to evaluate().
2617 
2618   The following are some examples to illustrate the behavior of
2619   canEvaluate(). (Note that all example inputs are assumed to have an
2620   explicit newline as their last character, since otherwise the
2621   Qt Script parser would automatically insert a semi-colon character at
2622   the end of the input, and this could cause canEvaluate() to produce
2623   different results.)
2624 
2625   Given the input
2626   \snippet code/src_script_qscriptengine.cpp 14
2627   canEvaluate() will return true, since the program appears to be complete.
2628 
2629   Given the input
2630   \snippet code/src_script_qscriptengine.cpp 15
2631   canEvaluate() will return false, since the if-statement is not complete,
2632   but is syntactically correct so far.
2633 
2634   Given the input
2635   \snippet code/src_script_qscriptengine.cpp 16
2636   canEvaluate() will return true, but evaluate() will throw a
2637   SyntaxError given the same input.
2638 
2639   Given the input
2640   \snippet code/src_script_qscriptengine.cpp 17
2641   canEvaluate() will return true, even though the code is clearly not
2642   syntactically valid Qt Script code. evaluate() will throw a
2643   SyntaxError when this code is evaluated.
2644 
2645   Given the input
2646   \snippet code/src_script_qscriptengine.cpp 18
2647   canEvaluate() will return true, but evaluate() will throw a
2648   ReferenceError if \c{foo} is not defined in the script
2649   environment.
2650 
2651   \sa evaluate(), checkSyntax()
2652 */
canEvaluate(const QString & program) const2653 bool QScriptEngine::canEvaluate(const QString &program) const
2654 {
2655     return QScriptEnginePrivate::canEvaluate(program);
2656 }
2657 
2658 
canEvaluate(const QString & program)2659 bool QScriptEnginePrivate::canEvaluate(const QString &program)
2660 {
2661     QScript::SyntaxChecker checker;
2662     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2663     return (result.state != QScript::SyntaxChecker::Intermediate);
2664 }
2665 
2666 /*!
2667   \since 4.5
2668 
2669   Checks the syntax of the given \a program. Returns a
2670   QScriptSyntaxCheckResult object that contains the result of the check.
2671 */
checkSyntax(const QString & program)2672 QScriptSyntaxCheckResult QScriptEngine::checkSyntax(const QString &program)
2673 {
2674     return QScriptEnginePrivate::checkSyntax(program);
2675 }
2676 
checkSyntax(const QString & program)2677 QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &program)
2678 {
2679     QScript::SyntaxChecker checker;
2680     QScript::SyntaxChecker::Result result = checker.checkSyntax(program);
2681     QScriptSyntaxCheckResultPrivate *p = new QScriptSyntaxCheckResultPrivate();
2682     switch (result.state) {
2683     case QScript::SyntaxChecker::Error:
2684         p->state = QScriptSyntaxCheckResult::Error;
2685         break;
2686     case QScript::SyntaxChecker::Intermediate:
2687         p->state = QScriptSyntaxCheckResult::Intermediate;
2688         break;
2689     case QScript::SyntaxChecker::Valid:
2690         p->state = QScriptSyntaxCheckResult::Valid;
2691         break;
2692     }
2693     p->errorLineNumber = result.errorLineNumber;
2694     p->errorColumnNumber = result.errorColumnNumber;
2695     p->errorMessage = result.errorMessage;
2696     return QScriptSyntaxCheckResult(p);
2697 }
2698 
2699 
2700 
2701 /*!
2702   Evaluates \a program, using \a lineNumber as the base line number,
2703   and returns the result of the evaluation.
2704 
2705   The script code will be evaluated in the current context.
2706 
2707   The evaluation of \a program can cause an exception in the
2708   engine; in this case the return value will be the exception
2709   that was thrown (typically an \c{Error} object). You can call
2710   hasUncaughtException() to determine if an exception occurred in
2711   the last call to evaluate().
2712 
2713   \a lineNumber is used to specify a starting line number for \a
2714   program; line number information reported by the engine that pertain
2715   to this evaluation (e.g. uncaughtExceptionLineNumber()) will be
2716   based on this argument. For example, if \a program consists of two
2717   lines of code, and the statement on the second line causes a script
2718   exception, uncaughtExceptionLineNumber() would return the given \a
2719   lineNumber plus one. When no starting line number is specified, line
2720   numbers will be 1-based.
2721 
2722   \a fileName is used for error reporting. For example in error objects
2723   the file name is accessible through the "fileName" property if it's
2724   provided with this function.
2725 
2726   \sa canEvaluate(), hasUncaughtException(), isEvaluating(), abortEvaluation()
2727 */
2728 
evaluate(const QString & program,const QString & fileName,int lineNumber)2729 QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber)
2730 {
2731     Q_D(QScriptEngine);
2732     QScript::APIShim shim(d);
2733     WTF::PassRefPtr<QScript::UStringSourceProviderWithFeedback> provider
2734             = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d);
2735     intptr_t sourceId = provider->asID();
2736     JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null.
2737 
2738     JSC::ExecState* exec = d->currentFrame;
2739     WTF::RefPtr<JSC::EvalExecutable> executable = JSC::EvalExecutable::create(exec, source);
2740     bool compile = true;
2741     return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, executable.get(), compile));
2742 }
2743 
2744 /*!
2745   \since 4.7
2746 
2747   Evaluates the given \a program and returns the result of the
2748   evaluation.
2749 */
evaluate(const QScriptProgram & program)2750 QScriptValue QScriptEngine::evaluate(const QScriptProgram &program)
2751 {
2752     Q_D(QScriptEngine);
2753     QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program);
2754     if (!program_d)
2755         return QScriptValue();
2756 
2757     QScript::APIShim shim(d);
2758     JSC::ExecState* exec = d->currentFrame;
2759     JSC::EvalExecutable *executable = program_d->executable(exec, d);
2760     bool compile = !program_d->isCompiled;
2761     JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId,
2762                                             executable, compile);
2763     if (compile)
2764         program_d->isCompiled = true;
2765     return d->scriptValueFromJSCValue(result);
2766 }
2767 
2768 /*!
2769   Returns the current context.
2770 
2771   The current context is typically accessed to retrieve the arguments
2772   and `this' object in native functions; for convenience, it is
2773   available as the first argument in QScriptEngine::FunctionSignature.
2774 */
currentContext() const2775 QScriptContext *QScriptEngine::currentContext() const
2776 {
2777     Q_D(const QScriptEngine);
2778     return const_cast<QScriptEnginePrivate*>(d)->contextForFrame(d->currentFrame);
2779 }
2780 
2781 /*!
2782   Enters a new execution context and returns the associated
2783   QScriptContext object.
2784 
2785   Once you are done with the context, you should call popContext() to
2786   restore the old context.
2787 
2788   By default, the `this' object of the new context is the Global Object.
2789   The context's \l{QScriptContext::callee()}{callee}() will be invalid.
2790 
2791   This function is useful when you want to evaluate script code
2792   as if it were the body of a function. You can use the context's
2793   \l{QScriptContext::activationObject()}{activationObject}() to initialize
2794   local variables that will be available to scripts. Example:
2795 
2796   \snippet code/src_script_qscriptengine.cpp 19
2797 
2798   In the above example, the new variable "tmp" defined in the script
2799   will be local to the context; in other words, the script doesn't
2800   have any effect on the global environment.
2801 
2802   Returns 0 in case of stack overflow
2803 
2804   \sa popContext()
2805 */
pushContext()2806 QScriptContext *QScriptEngine::pushContext()
2807 {
2808     Q_D(QScriptEngine);
2809     QScript::APIShim shim(d);
2810 
2811     JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject,
2812                                               JSC::ArgList(), /*callee = */0);
2813 
2814     if (agent())
2815         agent()->contextPush();
2816 
2817     return d->contextForFrame(newFrame);
2818 }
2819 
2820 /*! \internal
2821    push a context for a native function.
2822    JSC native function doesn't have different stackframe or context. so we need to create one.
2823 
2824    use popContext right after to go back to the previous context the context if no stack overflow has hapenned
2825 
2826    exec is the current top frame.
2827 
2828    return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow
2829 */
pushContext(JSC::CallFrame * exec,JSC::JSValue _thisObject,const JSC::ArgList & args,JSC::JSObject * callee,bool calledAsConstructor)2830 JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject,
2831                                                   const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor)
2832 {
2833     JSC::JSValue thisObject = _thisObject;
2834     if (!callee) {
2835         // callee can't be zero, as this can cause JSC to crash during GC
2836         // marking phase if the context's Arguments object has been created.
2837         // Fake it by using the global object. Note that this is also handled
2838         // in QScriptContext::callee(), as that function should still return
2839         // an invalid value.
2840         callee = originalGlobalObject();
2841     }
2842     if (calledAsConstructor) {
2843         //JSC doesn't create default created object for native functions. so we do it
2844         JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype);
2845         JSC::Structure *structure = prototype.isObject() ? JSC::asObject(prototype)->inheritorID()
2846                                                          : originalGlobalObject()->emptyObjectStructure();
2847         thisObject = new (exec) QScriptObject(structure);
2848     }
2849 
2850     int flags = NativeContext;
2851     if (calledAsConstructor)
2852         flags |= CalledAsConstructorContext;
2853 
2854     //build a frame
2855     JSC::CallFrame *newCallFrame = exec;
2856     if (callee == 0 //called from  public QScriptEngine::pushContext
2857         || exec->returnPC() == 0 || (contextFlags(exec) & NativeContext) //called from native-native call
2858         || exec->callee() != callee) { //the interpreter did not build a frame for us.
2859         //We need to check if the Interpreter might have already created a frame for function called from JS.
2860         JSC::Interpreter *interp = exec->interpreter();
2861         JSC::Register *oldEnd = interp->registerFile().end();
2862         int argc = args.size() + 1; //add "this"
2863         JSC::Register *newEnd = oldEnd + argc + JSC::RegisterFile::CallFrameHeaderSize;
2864         if (!interp->registerFile().grow(newEnd))
2865             return 0; //### Stack overflow
2866         newCallFrame = JSC::CallFrame::create(oldEnd);
2867         newCallFrame[0] = thisObject;
2868         int dst = 0;
2869         JSC::ArgList::const_iterator it;
2870         for (it = args.begin(); it != args.end(); ++it)
2871             newCallFrame[++dst] = *it;
2872         newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize;
2873 
2874         newCallFrame->init(0, /*vPC=*/0, globalExec()->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee);
2875     } else {
2876         setContextFlags(newCallFrame, flags);
2877 #if ENABLE(JIT)
2878         exec->registers()[JSC::RegisterFile::Callee] = JSC::JSValue(callee); //JIT let the callee set the 'callee'
2879 #endif
2880         if (calledAsConstructor) {
2881             //update the new created this
2882             JSC::Register* thisRegister = thisRegisterForFrame(newCallFrame);
2883             *thisRegister = thisObject;
2884         }
2885     }
2886     currentFrame = newCallFrame;
2887     return newCallFrame;
2888 }
2889 
2890 
2891 /*!
2892   Pops the current execution context and restores the previous one.
2893   This function must be used in conjunction with pushContext().
2894 
2895   \sa pushContext()
2896 */
popContext()2897 void QScriptEngine::popContext()
2898 {
2899     if (agent())
2900         agent()->contextPop();
2901     Q_D(QScriptEngine);
2902     QScript::APIShim shim(d);
2903     if (d->currentFrame->returnPC() != 0 || d->currentFrame->codeBlock() != 0
2904         || !currentContext()->parentContext()) {
2905         qWarning("QScriptEngine::popContext() doesn't match with pushContext()");
2906         return;
2907     }
2908 
2909     d->popContext();
2910 }
2911 
2912 /*! \internal
2913     counter part of QScriptEnginePrivate::pushContext
2914  */
popContext()2915 void QScriptEnginePrivate::popContext()
2916 {
2917     uint flags = contextFlags(currentFrame);
2918     bool hasScope = flags & HasScopeContext;
2919     if (flags & ShouldRestoreCallFrame) { //normal case
2920         JSC::RegisterFile &registerFile = currentFrame->interpreter()->registerFile();
2921         JSC::Register *const newEnd = currentFrame->registers() - JSC::RegisterFile::CallFrameHeaderSize - currentFrame->argumentCount();
2922         if (hasScope)
2923             currentFrame->scopeChain()->pop()->deref();
2924         registerFile.shrink(newEnd);
2925     } else if(hasScope) { //the stack frame was created by the Interpreter, we don't need to rewind it.
2926         currentFrame->setScopeChain(currentFrame->scopeChain()->pop());
2927         currentFrame->scopeChain()->deref();
2928     }
2929     currentFrame = currentFrame->callerFrame();
2930 }
2931 
2932 /*!
2933   Returns true if the last script evaluation resulted in an uncaught
2934   exception; otherwise returns false.
2935 
2936   The exception state is cleared when evaluate() is called.
2937 
2938   \sa uncaughtException(), uncaughtExceptionLineNumber()
2939 */
hasUncaughtException() const2940 bool QScriptEngine::hasUncaughtException() const
2941 {
2942     Q_D(const QScriptEngine);
2943     JSC::ExecState* exec = d->globalExec();
2944     return exec->hadException() || d->currentException().isValid();
2945 }
2946 
2947 /*!
2948   Returns the current uncaught exception, or an invalid QScriptValue
2949   if there is no uncaught exception.
2950 
2951   The exception value is typically an \c{Error} object; in that case,
2952   you can call toString() on the return value to obtain an error
2953   message.
2954 
2955   \sa hasUncaughtException(), uncaughtExceptionLineNumber(),
2956 */
uncaughtException() const2957 QScriptValue QScriptEngine::uncaughtException() const
2958 {
2959     Q_D(const QScriptEngine);
2960     QScriptValue result;
2961     JSC::ExecState* exec = d->globalExec();
2962     if (exec->hadException())
2963         result = const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(exec->exception());
2964     else
2965         result = d->currentException();
2966     return result;
2967 }
2968 
2969 /*!
2970   Returns the line number where the last uncaught exception occurred.
2971 
2972   Line numbers are 1-based, unless a different base was specified as
2973   the second argument to evaluate().
2974 
2975   \sa hasUncaughtException()
2976 */
uncaughtExceptionLineNumber() const2977 int QScriptEngine::uncaughtExceptionLineNumber() const
2978 {
2979     Q_D(const QScriptEngine);
2980     if (!hasUncaughtException())
2981         return -1;
2982     if (d->uncaughtExceptionLineNumber != -1)
2983         return d->uncaughtExceptionLineNumber;
2984 
2985     return uncaughtException().property(QLatin1String("lineNumber")).toInt32();
2986 }
2987 
2988 /*!
2989   Returns a human-readable backtrace of the last uncaught exception.
2990 
2991   It is in the form \c{<function-name>() at <file-name>:<line-number>}.
2992 
2993   \sa uncaughtException()
2994 */
uncaughtExceptionBacktrace() const2995 QStringList QScriptEngine::uncaughtExceptionBacktrace() const
2996 {
2997     Q_D(const QScriptEngine);
2998     return d->uncaughtExceptionBacktrace;
2999 }
3000 
3001 /*!
3002   \since 4.4
3003 
3004   Clears any uncaught exceptions in this engine.
3005 
3006   \sa hasUncaughtException()
3007 */
clearExceptions()3008 void QScriptEngine::clearExceptions()
3009 {
3010     Q_D(QScriptEngine);
3011     JSC::ExecState* exec = d->currentFrame;
3012     exec->clearException();
3013     d->clearCurrentException();
3014 }
3015 
3016 /*!
3017   Returns the default prototype associated with the given \a metaTypeId,
3018   or an invalid QScriptValue if no default prototype has been set.
3019 
3020   \sa setDefaultPrototype()
3021 */
defaultPrototype(int metaTypeId) const3022 QScriptValue QScriptEngine::defaultPrototype(int metaTypeId) const
3023 {
3024     Q_D(const QScriptEngine);
3025     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue(d->defaultPrototype(metaTypeId));
3026 }
3027 
3028 /*!
3029   Sets the default prototype of the C++ type identified by the given
3030   \a metaTypeId to \a prototype.
3031 
3032   The default prototype provides a script interface for values of
3033   type \a metaTypeId when a value of that type is accessed from script
3034   code.  Whenever the script engine (implicitly or explicitly) creates
3035   a QScriptValue from a value of type \a metaTypeId, the default
3036   prototype will be set as the QScriptValue's prototype.
3037 
3038   The \a prototype object itself may be constructed using one of two
3039   principal techniques; the simplest is to subclass QScriptable, which
3040   enables you to define the scripting API of the type through QObject
3041   properties and slots.  Another possibility is to create a script
3042   object by calling newObject(), and populate the object with the
3043   desired properties (e.g. native functions wrapped with
3044   newFunction()).
3045 
3046   \sa defaultPrototype(), qScriptRegisterMetaType(), QScriptable, {Default Prototypes Example}
3047 */
setDefaultPrototype(int metaTypeId,const QScriptValue & prototype)3048 void QScriptEngine::setDefaultPrototype(int metaTypeId, const QScriptValue &prototype)
3049 {
3050     Q_D(QScriptEngine);
3051     d->setDefaultPrototype(metaTypeId, d->scriptValueToJSCValue(prototype));
3052 }
3053 
3054 /*!
3055   \typedef QScriptEngine::FunctionSignature
3056 
3057   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *)}.
3058 
3059   A function with such a signature can be passed to
3060   QScriptEngine::newFunction() to wrap the function.
3061 */
3062 
3063 /*!
3064   \typedef QScriptEngine::FunctionWithArgSignature
3065 
3066   The function signature \c{QScriptValue f(QScriptContext *, QScriptEngine *, void *)}.
3067 
3068   A function with such a signature can be passed to
3069   QScriptEngine::newFunction() to wrap the function.
3070 */
3071 
3072 /*!
3073     \typedef QScriptEngine::MarshalFunction
3074     \internal
3075 */
3076 
3077 /*!
3078     \typedef QScriptEngine::DemarshalFunction
3079     \internal
3080 */
3081 
3082 /*!
3083     \internal
3084 */
create(int type,const void * ptr)3085 QScriptValue QScriptEngine::create(int type, const void *ptr)
3086 {
3087     Q_D(QScriptEngine);
3088     QScript::APIShim shim(d);
3089     return d->scriptValueFromJSCValue(d->create(d->currentFrame, type, ptr));
3090 }
3091 
create(JSC::ExecState * exec,int type,const void * ptr)3092 JSC::JSValue QScriptEnginePrivate::create(JSC::ExecState *exec, int type, const void *ptr)
3093 {
3094     Q_ASSERT(ptr != 0);
3095     JSC::JSValue result;
3096     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
3097     QScriptTypeInfo *info = eng ? eng->m_typeInfos.value(type) : 0;
3098     if (info && info->marshal) {
3099         result = eng->scriptValueToJSCValue(info->marshal(eng->q_func(), ptr));
3100     } else {
3101         // check if it's one of the types we know
3102         switch (QMetaType::Type(type)) {
3103         case QMetaType::UnknownType:
3104         case QMetaType::Void:
3105             return JSC::jsUndefined();
3106         case QMetaType::Bool:
3107             return JSC::jsBoolean(*reinterpret_cast<const bool*>(ptr));
3108         case QMetaType::Int:
3109             return JSC::jsNumber(exec, *reinterpret_cast<const int*>(ptr));
3110         case QMetaType::UInt:
3111             return JSC::jsNumber(exec, *reinterpret_cast<const uint*>(ptr));
3112         case QMetaType::Long:
3113             return JSC::jsNumber(exec, *reinterpret_cast<const long*>(ptr));
3114         case QMetaType::ULong:
3115             return JSC::jsNumber(exec, *reinterpret_cast<const ulong*>(ptr));
3116         case QMetaType::LongLong:
3117             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qlonglong*>(ptr)));
3118         case QMetaType::ULongLong:
3119             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const qulonglong*>(ptr)));
3120         case QMetaType::Double:
3121             return JSC::jsNumber(exec, qsreal(*reinterpret_cast<const double*>(ptr)));
3122         case QMetaType::QString:
3123             return JSC::jsString(exec, *reinterpret_cast<const QString*>(ptr));
3124         case QMetaType::Float:
3125             return JSC::jsNumber(exec, *reinterpret_cast<const float*>(ptr));
3126         case QMetaType::Short:
3127             return JSC::jsNumber(exec, *reinterpret_cast<const short*>(ptr));
3128         case QMetaType::UShort:
3129             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned short*>(ptr));
3130         case QMetaType::Char:
3131             return JSC::jsNumber(exec, *reinterpret_cast<const char*>(ptr));
3132         case QMetaType::UChar:
3133             return JSC::jsNumber(exec, *reinterpret_cast<const unsigned char*>(ptr));
3134         case QMetaType::QChar:
3135             return JSC::jsNumber(exec, (*reinterpret_cast<const QChar*>(ptr)).unicode());
3136         case QMetaType::QStringList:
3137             result = arrayFromStringList(exec, *reinterpret_cast<const QStringList *>(ptr));
3138             break;
3139         case QMetaType::QVariantList:
3140             result = arrayFromVariantList(exec, *reinterpret_cast<const QVariantList *>(ptr));
3141             break;
3142         case QMetaType::QVariantMap:
3143             result = objectFromVariantMap(exec, *reinterpret_cast<const QVariantMap *>(ptr));
3144             break;
3145         case QMetaType::QDateTime:
3146             result = newDate(exec, *reinterpret_cast<const QDateTime *>(ptr));
3147             break;
3148         case QMetaType::QDate:
3149             result = newDate(exec, QDateTime(*reinterpret_cast<const QDate *>(ptr)));
3150             break;
3151 #ifndef QT_NO_REGEXP
3152         case QMetaType::QRegExp:
3153             result = newRegExp(exec, *reinterpret_cast<const QRegExp *>(ptr));
3154             break;
3155 #endif
3156 #ifndef QT_NO_QOBJECT
3157         case QMetaType::QObjectStar:
3158             result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr));
3159             break;
3160 #endif
3161         case QMetaType::QVariant:
3162             result = eng->newVariant(*reinterpret_cast<const QVariant*>(ptr));
3163             break;
3164         default:
3165             if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
3166                 result = eng->newQObject(*reinterpret_cast<QObject* const *>(ptr));
3167                 break;
3168             }
3169 
3170             if (type == qMetaTypeId<QScriptValue>()) {
3171                 result = eng->scriptValueToJSCValue(*reinterpret_cast<const QScriptValue*>(ptr));
3172                 if (!result)
3173                     return JSC::jsUndefined();
3174             }
3175 
3176 #ifndef QT_NO_QOBJECT
3177             // lazy registration of some common list types
3178             else if (type == qMetaTypeId<QObjectList>()) {
3179                 qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3180                 return create(exec, type, ptr);
3181             }
3182 #endif
3183             else if (type == qMetaTypeId<QList<int> >()) {
3184                 qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3185                 return create(exec, type, ptr);
3186             }
3187 
3188             else {
3189                 QByteArray typeName = QMetaType::typeName(type);
3190                 if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
3191                     return JSC::jsNull();
3192                 else
3193                     result = eng->newVariant(QVariant(type, ptr));
3194             }
3195         }
3196     }
3197     if (result && result.isObject() && info && info->prototype
3198         && JSC::JSValue::strictEqual(exec, JSC::asObject(result)->prototype(), eng->originalGlobalObject()->objectPrototype())) {
3199         JSC::asObject(result)->setPrototype(info->prototype);
3200     }
3201     return result;
3202 }
3203 
convertValue(JSC::ExecState * exec,JSC::JSValue value,int type,void * ptr)3204 bool QScriptEnginePrivate::convertValue(JSC::ExecState *exec, JSC::JSValue value,
3205                                         int type, void *ptr)
3206 {
3207     QScriptEnginePrivate *eng = exec ? QScript::scriptEngineFromExec(exec) : 0;
3208     if (eng) {
3209         QScriptTypeInfo *info = eng->m_typeInfos.value(type);
3210         if (info && info->demarshal) {
3211             info->demarshal(eng->scriptValueFromJSCValue(value), ptr);
3212             return true;
3213         }
3214     }
3215 
3216     // check if it's one of the types we know
3217     switch (QMetaType::Type(type)) {
3218     case QMetaType::Bool:
3219         *reinterpret_cast<bool*>(ptr) = toBool(exec, value);
3220         return true;
3221     case QMetaType::Int:
3222         *reinterpret_cast<int*>(ptr) = toInt32(exec, value);
3223         return true;
3224     case QMetaType::UInt:
3225         *reinterpret_cast<uint*>(ptr) = toUInt32(exec, value);
3226         return true;
3227     case QMetaType::Long:
3228         *reinterpret_cast<long*>(ptr) = long(toInteger(exec, value));
3229         return true;
3230     case QMetaType::ULong:
3231         *reinterpret_cast<ulong*>(ptr) = ulong(toInteger(exec, value));
3232         return true;
3233     case QMetaType::LongLong:
3234         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(toInteger(exec, value));
3235         return true;
3236     case QMetaType::ULongLong:
3237         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(toInteger(exec, value));
3238         return true;
3239     case QMetaType::Double:
3240         *reinterpret_cast<double*>(ptr) = toNumber(exec, value);
3241         return true;
3242     case QMetaType::QString:
3243         if (value.isUndefined() || value.isNull())
3244             *reinterpret_cast<QString*>(ptr) = QString();
3245         else
3246             *reinterpret_cast<QString*>(ptr) = toString(exec, value);
3247         return true;
3248     case QMetaType::Float:
3249         *reinterpret_cast<float*>(ptr) = toNumber(exec, value);
3250         return true;
3251     case QMetaType::Short:
3252         *reinterpret_cast<short*>(ptr) = short(toInt32(exec, value));
3253         return true;
3254     case QMetaType::UShort:
3255         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(toNumber(exec, value));
3256         return true;
3257     case QMetaType::Char:
3258         *reinterpret_cast<char*>(ptr) = char(toInt32(exec, value));
3259         return true;
3260     case QMetaType::UChar:
3261         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(toInt32(exec, value));
3262         return true;
3263     case QMetaType::QChar:
3264         if (value.isString()) {
3265             QString str = toString(exec, value);
3266             *reinterpret_cast<QChar*>(ptr) = str.isEmpty() ? QChar() : str.at(0);
3267         } else {
3268             *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(toNumber(exec, value)));
3269         }
3270         return true;
3271     case QMetaType::QDateTime:
3272         if (isDate(value)) {
3273             *reinterpret_cast<QDateTime *>(ptr) = toDateTime(exec, value);
3274             return true;
3275         } break;
3276     case QMetaType::QDate:
3277         if (isDate(value)) {
3278             *reinterpret_cast<QDate *>(ptr) = toDateTime(exec, value).date();
3279             return true;
3280         } break;
3281 #ifndef QT_NO_REGEXP
3282     case QMetaType::QRegExp:
3283         if (isRegExp(value)) {
3284             *reinterpret_cast<QRegExp *>(ptr) = toRegExp(exec, value);
3285             return true;
3286         } break;
3287 #endif
3288 #ifndef QT_NO_QOBJECT
3289     case QMetaType::QObjectStar:
3290         if (isQObject(value) || value.isNull()) {
3291             *reinterpret_cast<QObject* *>(ptr) = toQObject(exec, value);
3292             return true;
3293         } break;
3294 #endif
3295     case QMetaType::QStringList:
3296         if (isArray(value)) {
3297             *reinterpret_cast<QStringList *>(ptr) = stringListFromArray(exec, value);
3298             return true;
3299         } break;
3300     case QMetaType::QVariantList:
3301         if (isArray(value)) {
3302             *reinterpret_cast<QVariantList *>(ptr) = variantListFromArray(exec, JSC::asArray(value));
3303             return true;
3304         } break;
3305     case QMetaType::QVariantMap:
3306         if (isObject(value)) {
3307             *reinterpret_cast<QVariantMap *>(ptr) = variantMapFromObject(exec, JSC::asObject(value));
3308             return true;
3309         } break;
3310     case QMetaType::QVariant:
3311         *reinterpret_cast<QVariant*>(ptr) = toVariant(exec, value);
3312         return true;
3313     default:
3314     ;
3315     }
3316 
3317     QByteArray name = QMetaType::typeName(type);
3318 #ifndef QT_NO_QOBJECT
3319     if (convertToNativeQObject(exec, value, name, reinterpret_cast<void* *>(ptr)))
3320         return true;
3321 #endif
3322     if (isVariant(value) && name.endsWith('*')) {
3323         int valueType = QMetaType::type(name.left(name.size()-1));
3324         QVariant &var = variantValue(value);
3325         if (valueType == var.userType()) {
3326             *reinterpret_cast<void* *>(ptr) = var.data();
3327             return true;
3328         } else {
3329             // look in the prototype chain
3330             JSC::JSValue proto = JSC::asObject(value)->prototype();
3331             while (proto.isObject()) {
3332                 bool canCast = false;
3333                 if (isVariant(proto)) {
3334                     canCast = (type == variantValue(proto).userType())
3335                               || (valueType && (valueType == variantValue(proto).userType()));
3336                 }
3337 #ifndef QT_NO_QOBJECT
3338                 else if (isQObject(proto)) {
3339                     QByteArray className = name.left(name.size()-1);
3340                     if (QObject *qobject = toQObject(exec, proto))
3341                         canCast = qobject->qt_metacast(className) != 0;
3342                 }
3343 #endif
3344                 if (canCast) {
3345                     QByteArray varTypeName = QMetaType::typeName(var.userType());
3346                     if (varTypeName.endsWith('*'))
3347                         *reinterpret_cast<void* *>(ptr) = *reinterpret_cast<void* *>(var.data());
3348                     else
3349                         *reinterpret_cast<void* *>(ptr) = var.data();
3350                     return true;
3351                 }
3352                 proto = JSC::asObject(proto)->prototype();
3353             }
3354         }
3355     } else if (value.isNull() && name.endsWith('*')) {
3356         *reinterpret_cast<void* *>(ptr) = 0;
3357         return true;
3358     } else if (type == qMetaTypeId<QScriptValue>()) {
3359         if (!eng)
3360             return false;
3361         *reinterpret_cast<QScriptValue*>(ptr) = eng->scriptValueFromJSCValue(value);
3362         return true;
3363     }
3364 
3365     // lazy registration of some common list types
3366 #ifndef QT_NO_QOBJECT
3367     else if (type == qMetaTypeId<QObjectList>()) {
3368         if (!eng)
3369             return false;
3370         qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
3371         return convertValue(exec, value, type, ptr);
3372     }
3373 #endif
3374     else if (type == qMetaTypeId<QList<int> >()) {
3375         if (!eng)
3376             return false;
3377         qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
3378         return convertValue(exec, value, type, ptr);
3379     }
3380 
3381 #if 0
3382     if (!name.isEmpty()) {
3383         qWarning("QScriptEngine::convert: unable to convert value to type `%s'",
3384                  name.constData());
3385     }
3386 #endif
3387     return false;
3388 }
3389 
convertNumber(qsreal value,int type,void * ptr)3390 bool QScriptEnginePrivate::convertNumber(qsreal value, int type, void *ptr)
3391 {
3392     switch (QMetaType::Type(type)) {
3393     case QMetaType::Bool:
3394         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3395         return true;
3396     case QMetaType::Int:
3397         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3398         return true;
3399     case QMetaType::UInt:
3400         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3401         return true;
3402     case QMetaType::Long:
3403         *reinterpret_cast<long*>(ptr) = long(QScript::ToInteger(value));
3404         return true;
3405     case QMetaType::ULong:
3406         *reinterpret_cast<ulong*>(ptr) = ulong(QScript::ToInteger(value));
3407         return true;
3408     case QMetaType::LongLong:
3409         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3410         return true;
3411     case QMetaType::ULongLong:
3412         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3413         return true;
3414     case QMetaType::Double:
3415         *reinterpret_cast<double*>(ptr) = value;
3416         return true;
3417     case QMetaType::QString:
3418         *reinterpret_cast<QString*>(ptr) = QScript::ToString(value);
3419         return true;
3420     case QMetaType::Float:
3421         *reinterpret_cast<float*>(ptr) = value;
3422         return true;
3423     case QMetaType::Short:
3424         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3425         return true;
3426     case QMetaType::UShort:
3427         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3428         return true;
3429     case QMetaType::Char:
3430         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3431         return true;
3432     case QMetaType::UChar:
3433         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3434         return true;
3435     case QMetaType::QChar:
3436         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3437         return true;
3438     default:
3439         break;
3440     }
3441     return false;
3442 }
3443 
convertString(const QString & value,int type,void * ptr)3444 bool QScriptEnginePrivate::convertString(const QString &value, int type, void *ptr)
3445 {
3446     switch (QMetaType::Type(type)) {
3447     case QMetaType::Bool:
3448         *reinterpret_cast<bool*>(ptr) = QScript::ToBool(value);
3449         return true;
3450     case QMetaType::Int:
3451         *reinterpret_cast<int*>(ptr) = QScript::ToInt32(value);
3452         return true;
3453     case QMetaType::UInt:
3454         *reinterpret_cast<uint*>(ptr) = QScript::ToUInt32(value);
3455         return true;
3456     case QMetaType::Long:
3457         *reinterpret_cast<long*>(ptr) = long(QScript::ToInteger(value));
3458         return true;
3459     case QMetaType::ULong:
3460         *reinterpret_cast<ulong*>(ptr) = ulong(QScript::ToInteger(value));
3461         return true;
3462     case QMetaType::LongLong:
3463         *reinterpret_cast<qlonglong*>(ptr) = qlonglong(QScript::ToInteger(value));
3464         return true;
3465     case QMetaType::ULongLong:
3466         *reinterpret_cast<qulonglong*>(ptr) = qulonglong(QScript::ToInteger(value));
3467         return true;
3468     case QMetaType::Double:
3469         *reinterpret_cast<double*>(ptr) = QScript::ToNumber(value);
3470         return true;
3471     case QMetaType::QString:
3472         *reinterpret_cast<QString*>(ptr) = value;
3473         return true;
3474     case QMetaType::Float:
3475         *reinterpret_cast<float*>(ptr) = QScript::ToNumber(value);
3476         return true;
3477     case QMetaType::Short:
3478         *reinterpret_cast<short*>(ptr) = short(QScript::ToInt32(value));
3479         return true;
3480     case QMetaType::UShort:
3481         *reinterpret_cast<unsigned short*>(ptr) = QScript::ToUInt16(value);
3482         return true;
3483     case QMetaType::Char:
3484         *reinterpret_cast<char*>(ptr) = char(QScript::ToInt32(value));
3485         return true;
3486     case QMetaType::UChar:
3487         *reinterpret_cast<unsigned char*>(ptr) = (unsigned char)(QScript::ToInt32(value));
3488         return true;
3489     case QMetaType::QChar:
3490         *reinterpret_cast<QChar*>(ptr) = QChar(QScript::ToUInt16(value));
3491         return true;
3492     default:
3493         break;
3494     }
3495     return false;
3496 }
3497 
hasDemarshalFunction(int type) const3498 bool QScriptEnginePrivate::hasDemarshalFunction(int type) const
3499 {
3500     QScriptTypeInfo *info = m_typeInfos.value(type);
3501     return info && (info->demarshal != 0);
3502 }
3503 
translationContextFromUrl(const JSC::UString & url)3504 JSC::UString QScriptEnginePrivate::translationContextFromUrl(const JSC::UString &url)
3505 {
3506     if (url != cachedTranslationUrl) {
3507         const QString &baseName = QFileInfo(url).baseName();
3508         if (baseName.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive))
3509             cachedTranslationContext = baseName.mid(4);
3510         else
3511             cachedTranslationContext = baseName;
3512 
3513         cachedTranslationUrl = url;
3514     }
3515     return cachedTranslationContext;
3516 }
3517 
3518 /*!
3519     \internal
3520 */
convert(const QScriptValue & value,int type,void * ptr)3521 bool QScriptEngine::convert(const QScriptValue &value, int type, void *ptr)
3522 {
3523     Q_D(QScriptEngine);
3524     QScript::APIShim shim(d);
3525     return QScriptEnginePrivate::convertValue(d->currentFrame, d->scriptValueToJSCValue(value), type, ptr);
3526 }
3527 
3528 /*!
3529     \internal
3530 */
convertV2(const QScriptValue & value,int type,void * ptr)3531 bool QScriptEngine::convertV2(const QScriptValue &value, int type, void *ptr)
3532 {
3533     QScriptValuePrivate *vp = QScriptValuePrivate::get(value);
3534     if (vp) {
3535         switch (vp->type) {
3536         case QScriptValuePrivate::JavaScriptCore: {
3537             if (vp->engine) {
3538                 QScript::APIShim shim(vp->engine);
3539                 return QScriptEnginePrivate::convertValue(vp->engine->currentFrame, vp->jscValue, type, ptr);
3540             } else {
3541                 return QScriptEnginePrivate::convertValue(0, vp->jscValue, type, ptr);
3542             }
3543         }
3544         case QScriptValuePrivate::Number:
3545             return QScriptEnginePrivate::convertNumber(vp->numberValue, type, ptr);
3546         case QScriptValuePrivate::String:
3547             return QScriptEnginePrivate::convertString(vp->stringValue, type, ptr);
3548         }
3549     }
3550     return false;
3551 }
3552 
3553 /*!
3554     \internal
3555 */
registerCustomType(int type,MarshalFunction mf,DemarshalFunction df,const QScriptValue & prototype)3556 void QScriptEngine::registerCustomType(int type, MarshalFunction mf,
3557                                        DemarshalFunction df,
3558                                        const QScriptValue &prototype)
3559 {
3560     Q_D(QScriptEngine);
3561     QScript::APIShim shim(d);
3562     QScriptTypeInfo *info = d->m_typeInfos.value(type);
3563     if (!info) {
3564         info = new QScriptTypeInfo();
3565         d->m_typeInfos.insert(type, info);
3566     }
3567     info->marshal = mf;
3568     info->demarshal = df;
3569     info->prototype = d->scriptValueToJSCValue(prototype);
3570 }
3571 
3572 /*!
3573   \since 4.5
3574 
3575   Installs translator functions on the given \a object, or on the Global
3576   Object if no object is specified.
3577 
3578   The relation between Qt Script translator functions and C++ translator
3579   functions is described in the following table:
3580 
3581     \table
3582     \header \li Script Function \li Corresponding C++ Function
3583     \row    \li qsTr()       \li QObject::tr()
3584     \row    \li QT_TR_NOOP() \li QT_TR_NOOP()
3585     \row    \li qsTranslate() \li QCoreApplication::translate()
3586     \row    \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP()
3587     \row    \li qsTrId() (since 4.7) \li qtTrId()
3588     \row    \li QT_TRID_NOOP() (since 4.7) \li QT_TRID_NOOP()
3589     \endtable
3590 
3591   \sa {Internationalization with Qt}
3592 */
installTranslatorFunctions(const QScriptValue & object)3593 void QScriptEngine::installTranslatorFunctions(const QScriptValue &object)
3594 {
3595     Q_D(QScriptEngine);
3596     QScript::APIShim shim(d);
3597     JSC::ExecState* exec = d->currentFrame;
3598     JSC::JSValue jscObject = d->scriptValueToJSCValue(object);
3599     JSC::JSGlobalObject *glob = d->originalGlobalObject();
3600     if (!jscObject || !jscObject.isObject())
3601         jscObject = d->globalObject();
3602 //    unsigned attribs = JSC::DontEnum;
3603 
3604 #ifndef QT_NO_TRANSLATION
3605     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 5, JSC::Identifier(exec, "qsTranslate"), QScript::functionQsTranslate));
3606     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 2, JSC::Identifier(exec, "QT_TRANSLATE_NOOP"), QScript::functionQsTranslateNoOp));
3607     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 3, JSC::Identifier(exec, "qsTr"), QScript::functionQsTr));
3608     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TR_NOOP"), QScript::functionQsTrNoOp));
3609     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "qsTrId"), QScript::functionQsTrId));
3610     JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TRID_NOOP"), QScript::functionQsTrIdNoOp));
3611 #endif
3612 
3613     glob->stringPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "arg"), QScript::stringProtoFuncArg));
3614 }
3615 
3616 /*!
3617     Imports the given \a extension into this QScriptEngine.  Returns
3618     undefinedValue() if the extension was successfully imported. You
3619     can call hasUncaughtException() to check if an error occurred; in
3620     that case, the return value is the value that was thrown by the
3621     exception (usually an \c{Error} object).
3622 
3623     QScriptEngine ensures that a particular extension is only imported
3624     once; subsequent calls to importExtension() with the same extension
3625     name will do nothing and return undefinedValue().
3626 
3627     \sa availableExtensions(), QScriptExtensionPlugin, {Creating Qt Script Extensions}
3628 */
importExtension(const QString & extension)3629 QScriptValue QScriptEngine::importExtension(const QString &extension)
3630 {
3631 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
3632     Q_UNUSED(extension);
3633 #else
3634     Q_D(QScriptEngine);
3635     QScript::APIShim shim(d);
3636     if (d->importedExtensions.contains(extension))
3637         return undefinedValue(); // already imported
3638 
3639     QScriptContext *context = currentContext();
3640     QCoreApplication *app = QCoreApplication::instance();
3641     if (!app)
3642         return context->throwError(QLatin1String("No application object"));
3643 
3644     QObjectList staticPlugins = QPluginLoader::staticInstances();
3645     QStringList libraryPaths = app->libraryPaths();
3646     QString dot = QLatin1String(".");
3647     QStringList pathComponents = extension.split(dot);
3648     QString initDotJs = QLatin1String("__init__.js");
3649 
3650     QString ext;
3651     for (int i = 0; i < pathComponents.count(); ++i) {
3652         if (!ext.isEmpty())
3653             ext.append(dot);
3654         ext.append(pathComponents.at(i));
3655         if (d->importedExtensions.contains(ext))
3656             continue; // already imported
3657 
3658         if (d->extensionsBeingImported.contains(ext)) {
3659             return context->throwError(QString::fromLatin1("recursive import of %0")
3660                                        .arg(extension));
3661         }
3662         d->extensionsBeingImported.insert(ext);
3663 
3664         QScriptExtensionInterface *iface = 0;
3665         QString initjsContents;
3666         QString initjsFileName;
3667 
3668         // look for the extension in static plugins
3669         for (int j = 0; j < staticPlugins.size(); ++j) {
3670             iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(j));
3671             if (!iface)
3672                 continue;
3673             if (iface->keys().contains(ext))
3674                 break; // use this one
3675             else
3676                 iface = 0; // keep looking
3677         }
3678 
3679         {
3680             // look for __init__.js resource
3681             QString path = QString::fromLatin1(":/qtscriptextension");
3682             for (int j = 0; j <= i; ++j) {
3683                 path.append(QLatin1Char('/'));
3684                 path.append(pathComponents.at(j));
3685             }
3686             path.append(QLatin1Char('/'));
3687             path.append(initDotJs);
3688             QFile file(path);
3689             if (file.open(QIODevice::ReadOnly)) {
3690                 QTextStream ts(&file);
3691                 initjsContents = ts.readAll();
3692                 initjsFileName = path;
3693                 file.close();
3694             }
3695         }
3696 
3697         if (!iface && initjsContents.isEmpty()) {
3698             // look for the extension in library paths
3699             for (int j = 0; j < libraryPaths.count(); ++j) {
3700                 QString libPath = libraryPaths.at(j) + QDir::separator() + QLatin1String("script");
3701                 QDir dir(libPath);
3702                 if (!dir.exists(dot))
3703                     continue;
3704 
3705                 // look for C++ plugin
3706                 QFileInfoList files = dir.entryInfoList(QDir::Files);
3707                 for (int k = 0; k < files.count(); ++k) {
3708                     QFileInfo entry = files.at(k);
3709                     QString filePath = entry.canonicalFilePath();
3710                     QPluginLoader loader(filePath);
3711                     iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
3712                     if (iface) {
3713                         if (iface->keys().contains(ext))
3714                             break; // use this one
3715                         else
3716                             iface = 0; // keep looking
3717                     }
3718                 }
3719 
3720                 // look for __init__.js in the corresponding dir
3721                 QDir dirdir(libPath);
3722                 bool dirExists = dirdir.exists();
3723                 for (int k = 0; dirExists && (k <= i); ++k)
3724                     dirExists = dirdir.cd(pathComponents.at(k));
3725                 if (dirExists && dirdir.exists(initDotJs)) {
3726                     QFile file(dirdir.canonicalPath()
3727                                + QDir::separator() + initDotJs);
3728                     if (file.open(QIODevice::ReadOnly)) {
3729                         QTextStream ts(&file);
3730                         initjsContents = ts.readAll();
3731                         initjsFileName = file.fileName();
3732                         file.close();
3733                     }
3734                 }
3735 
3736                 if (iface || !initjsContents.isEmpty())
3737                     break;
3738             }
3739         }
3740 
3741         if (!iface && initjsContents.isEmpty()) {
3742             d->extensionsBeingImported.remove(ext);
3743             return context->throwError(
3744                 QString::fromLatin1("Unable to import %0: no such extension")
3745                 .arg(extension));
3746         }
3747 
3748         // initialize the extension in a new context
3749         QScriptContext *ctx = pushContext();
3750         ctx->setThisObject(globalObject());
3751         ctx->activationObject().setProperty(QLatin1String("__extension__"), ext,
3752                                             QScriptValue::ReadOnly | QScriptValue::Undeletable);
3753         ctx->activationObject().setProperty(QLatin1String("__setupPackage__"),
3754                                             newFunction(QScript::__setupPackage__));
3755         ctx->activationObject().setProperty(QLatin1String("__postInit__"), QScriptValue(QScriptValue::UndefinedValue));
3756 
3757         // the script is evaluated first
3758         if (!initjsContents.isEmpty()) {
3759             QScriptValue ret = evaluate(initjsContents, initjsFileName);
3760             if (hasUncaughtException()) {
3761                 popContext();
3762                 d->extensionsBeingImported.remove(ext);
3763                 return ret;
3764             }
3765         }
3766 
3767         // next, the C++ plugin is called
3768         if (iface) {
3769             iface->initialize(ext, this);
3770             if (hasUncaughtException()) {
3771                 QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
3772                 popContext();
3773                 d->extensionsBeingImported.remove(ext);
3774                 return ret;
3775             }
3776         }
3777 
3778         // if the __postInit__ function has been set, we call it
3779         QScriptValue postInit = ctx->activationObject().property(QLatin1String("__postInit__"));
3780         if (postInit.isFunction()) {
3781             postInit.call(globalObject());
3782             if (hasUncaughtException()) {
3783                 QScriptValue ret = uncaughtException(); // ctx_p->returnValue();
3784                 popContext();
3785                 d->extensionsBeingImported.remove(ext);
3786                 return ret;
3787             }
3788         }
3789 
3790         popContext();
3791 
3792         d->importedExtensions.insert(ext);
3793         d->extensionsBeingImported.remove(ext);
3794     } // for (i)
3795 #endif // QT_NO_QOBJECT
3796     return undefinedValue();
3797 }
3798 
3799 /*!
3800     \since 4.4
3801 
3802     Returns a list naming the available extensions that can be
3803     imported using the importExtension() function. This list includes
3804     extensions that have been imported.
3805 
3806     \sa importExtension(), importedExtensions()
3807 */
availableExtensions() const3808 QStringList QScriptEngine::availableExtensions() const
3809 {
3810 #if defined(QT_NO_QOBJECT) || defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
3811     return QStringList();
3812 #else
3813     QCoreApplication *app = QCoreApplication::instance();
3814     if (!app)
3815         return QStringList();
3816 
3817     QSet<QString> result;
3818 
3819     QObjectList staticPlugins = QPluginLoader::staticInstances();
3820     for (int i = 0; i < staticPlugins.size(); ++i) {
3821         QScriptExtensionInterface *iface;
3822         iface = qobject_cast<QScriptExtensionInterface*>(staticPlugins.at(i));
3823         if (iface) {
3824             QStringList keys = iface->keys();
3825             for (int j = 0; j < keys.count(); ++j)
3826                 result << keys.at(j);
3827         }
3828     }
3829 
3830     QStringList libraryPaths = app->libraryPaths();
3831     for (int i = 0; i < libraryPaths.count(); ++i) {
3832         QString libPath = libraryPaths.at(i) + QDir::separator() + QLatin1String("script");
3833         QDir dir(libPath);
3834         if (!dir.exists())
3835             continue;
3836 
3837         // look for C++ plugins
3838         QFileInfoList files = dir.entryInfoList(QDir::Files);
3839         for (int j = 0; j < files.count(); ++j) {
3840             QFileInfo entry = files.at(j);
3841             QString filePath = entry.canonicalFilePath();
3842             QPluginLoader loader(filePath);
3843             QScriptExtensionInterface *iface;
3844             iface = qobject_cast<QScriptExtensionInterface*>(loader.instance());
3845             if (iface) {
3846                 QStringList keys = iface->keys();
3847                 for (int k = 0; k < keys.count(); ++k)
3848                     result << keys.at(k);
3849             }
3850         }
3851 
3852         // look for scripts
3853         QString initDotJs = QLatin1String("__init__.js");
3854         QList<QFileInfo> stack;
3855         stack << dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
3856         while (!stack.isEmpty()) {
3857             QFileInfo entry = stack.takeLast();
3858             QDir dd(entry.canonicalFilePath());
3859             if (dd.exists(initDotJs)) {
3860                 QString rpath = dir.relativeFilePath(dd.canonicalPath());
3861                 QStringList components = rpath.split(QLatin1Char('/'));
3862                 result << components.join(QLatin1String("."));
3863                 stack << dd.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
3864             }
3865         }
3866     }
3867 
3868     QStringList lst = result.toList();
3869     std::sort(lst.begin(), lst.end());
3870     return lst;
3871 #endif
3872 }
3873 
3874 /*!
3875     \since 4.4
3876 
3877     Returns a list naming the extensions that have been imported
3878     using the importExtension() function.
3879 
3880     \sa availableExtensions()
3881 */
importedExtensions() const3882 QStringList QScriptEngine::importedExtensions() const
3883 {
3884     Q_D(const QScriptEngine);
3885     QStringList lst = d->importedExtensions.toList();
3886     std::sort(lst.begin(), lst.end());
3887     return lst;
3888 }
3889 
3890 /*! \fn template <typename T> QScriptValue QScriptEngine::toScriptValue(const T &value)
3891 
3892     Creates a QScriptValue with the given \a value.
3893 
3894     Note that the template type \c{T} must be known to QMetaType.
3895 
3896     See \l{Conversion Between Qt Script and C++ Types} for a
3897     description of the built-in type conversion provided by
3898     Qt Script. By default, the types that are not specially handled by
3899     Qt Script are represented as QVariants (e.g. the \a value is passed
3900     to newVariant()); you can change this behavior by installing your
3901     own type conversion functions with qScriptRegisterMetaType().
3902 
3903     \sa fromScriptValue(), qScriptRegisterMetaType()
3904 */
3905 
3906 /*! \fn template <typename T> T QScriptEngine::fromScriptValue(const QScriptValue &value)
3907 
3908     Returns the given \a value converted to the template type \c{T}.
3909 
3910     Note that \c{T} must be known to QMetaType.
3911 
3912     See \l{Conversion Between Qt Script and C++ Types} for a
3913     description of the built-in type conversion provided by
3914     Qt Script.
3915 
3916     \sa toScriptValue(), qScriptRegisterMetaType()
3917 */
3918 
3919 /*!
3920     \fn template <typename T> QScriptValue qScriptValueFromValue(QScriptEngine *engine, const T &value)
3921     \since 4.3
3922     \relates QScriptEngine
3923     \obsolete
3924 
3925     Creates a QScriptValue using the given \a engine with the given \a
3926     value of template type \c{T}.
3927 
3928     This function is equivalent to QScriptEngine::toScriptValue().
3929 
3930     \note This function was provided as a workaround for MSVC 6
3931     which did not support member template functions. It is advised
3932     to use the other form in new code.
3933 
3934     \sa QScriptEngine::toScriptValue(), qscriptvalue_cast()
3935 */
3936 
3937 /*!
3938     \fn template <typename T> T qScriptValueToValue(const QScriptValue &value)
3939     \since 4.3
3940     \relates QScriptEngine
3941     \obsolete
3942 
3943     Returns the given \a value converted to the template type \c{T}.
3944 
3945     This function is equivalent to QScriptEngine::fromScriptValue().
3946 
3947     \note This function was provided as a workaround for MSVC 6
3948     which did not support member template functions. It is advised
3949     to use the other form in new code.
3950 
3951     \sa QScriptEngine::fromScriptValue()
3952 */
3953 
3954 /*!
3955     \fn template <class Container> QScriptValue qScriptValueFromSequence(QScriptEngine *engine, const Container &container)
3956     \since 4.3
3957     \relates QScriptEngine
3958 
3959     Creates an array in the form of a QScriptValue using the given \a engine
3960     with the given \a container of template type \c{Container}.
3961 
3962     The \c Container type must provide a \c const_iterator class to enable the
3963     contents of the container to be copied into the array.
3964 
3965     Additionally, the type of each element in the sequence should be
3966     suitable for conversion to a QScriptValue.  See
3967     \l{Conversion Between Qt Script and C++ Types} for more information
3968     about the restrictions on types that can be used with QScriptValue.
3969 
3970     \sa QScriptEngine::fromScriptValue()
3971 */
3972 
3973 /*!
3974     \fn template <class Container> void qScriptValueToSequence(const QScriptValue &value, Container &container)
3975     \since 4.3
3976     \relates QScriptEngine
3977 
3978     Copies the elements in the sequence specified by \a value to the given
3979     \a container of template type \c{Container}.
3980 
3981     The \a value used is typically an array, but any container can be copied
3982     as long as it provides a \c length property describing how many elements
3983     it contains.
3984 
3985     Additionally, the type of each element in the sequence must be
3986     suitable for conversion to a C++ type from a QScriptValue.  See
3987     \l{Conversion Between Qt Script and C++ Types} for more information
3988     about the restrictions on types that can be used with
3989     QScriptValue.
3990 
3991     \sa qscriptvalue_cast()
3992 */
3993 
3994 /*!
3995     \fn template <typename T> T qscriptvalue_cast(const QScriptValue &value)
3996     \since 4.3
3997     \relates QScriptValue
3998 
3999     Returns the given \a value converted to the template type \c{T}.
4000 
4001     \sa qScriptRegisterMetaType(), QScriptEngine::toScriptValue()
4002 */
4003 
4004 /*! \fn template<typename T> int qScriptRegisterMetaType(
4005             QScriptEngine *eng,
4006             QScriptValue (*toScriptValue)(QScriptEngine *, const T &t),
4007             void (*fromScriptValue)(const QScriptValue &, T &t),
4008             const QScriptValue &prototype, T *)
4009 
4010     \relates QScriptEngine
4011 
4012     Registers the type \c{T} in the given \a eng. \a toScriptValue must
4013     be a function that will convert from a value of type \c{T} to a
4014     QScriptValue, and \a fromScriptValue a function that does the
4015     opposite. \a prototype, if valid, is the prototype that's set on
4016     QScriptValues returned by \a toScriptValue.
4017 
4018     Returns the internal ID used by QMetaType.
4019 
4020     You only need to call this function if you want to provide custom
4021     conversion of values of type \c{T}, i.e. if the default
4022     QVariant-based representation and conversion is not
4023     appropriate. (Note that custom QObject-derived types also fall in
4024     this category; e.g. for a QObject-derived class called MyObject,
4025     you probably want to define conversion functions for MyObject*
4026     that utilize QScriptEngine::newQObject() and
4027     QScriptValue::toQObject().)
4028 
4029     If you only want to define a common script interface for values of
4030     type \c{T}, and don't care how those values are represented
4031     (i.e. storing them in QVariants is fine), use
4032     \l{QScriptEngine::setDefaultPrototype()}{setDefaultPrototype}()
4033     instead; this will minimize conversion costs.
4034 
4035     You need to declare the custom type first with
4036     Q_DECLARE_METATYPE().
4037 
4038     After a type has been registered, you can convert from a
4039     QScriptValue to that type using
4040     \l{QScriptEngine::fromScriptValue()}{fromScriptValue}(), and
4041     create a QScriptValue from a value of that type using
4042     \l{QScriptEngine::toScriptValue()}{toScriptValue}(). The engine
4043     will take care of calling the proper conversion function when
4044     calling C++ slots, and when getting or setting a C++ property;
4045     i.e. the custom type may be used seamlessly on both the C++ side
4046     and the script side.
4047 
4048     The following is an example of how to use this function. We will
4049     specify custom conversion of our type \c{MyStruct}. Here's the C++
4050     type:
4051 
4052     \snippet code/src_script_qscriptengine.cpp 20
4053 
4054     We must declare it so that the type will be known to QMetaType:
4055 
4056     \snippet code/src_script_qscriptengine.cpp 21
4057 
4058     Next, the \c{MyStruct} conversion functions. We represent the
4059     \c{MyStruct} value as a script object and just copy the properties:
4060 
4061     \snippet code/src_script_qscriptengine.cpp 22
4062 
4063     Now we can register \c{MyStruct} with the engine:
4064     \snippet code/src_script_qscriptengine.cpp 23
4065 
4066     Working with \c{MyStruct} values is now easy:
4067     \snippet code/src_script_qscriptengine.cpp 24
4068 
4069     If you want to be able to construct values of your custom type
4070     from script code, you have to register a constructor function for
4071     the type. For example:
4072 
4073     \snippet code/src_script_qscriptengine.cpp 25
4074 
4075     \sa qScriptRegisterSequenceMetaType(), qRegisterMetaType()
4076 */
4077 
4078 /*!
4079     \macro Q_SCRIPT_DECLARE_QMETAOBJECT(QMetaObject, ArgType)
4080     \since 4.3
4081     \relates QScriptEngine
4082 
4083     Declares the given \a QMetaObject. Used in combination with
4084     QScriptEngine::scriptValueFromQMetaObject() to make enums and
4085     instantiation of \a QMetaObject available to script code. The
4086     constructor generated by this macro takes a single argument of
4087     type \a ArgType; typically the argument is the parent type of the
4088     new instance, in which case \a ArgType is \c{QWidget*} or
4089     \c{QObject*}. Objects created by the constructor will have
4090     QScriptEngine::AutoOwnership ownership.
4091 */
4092 
4093 /*!
4094     \fn template<typename T> int qScriptRegisterSequenceMetaType(
4095             QScriptEngine *engine,
4096             const QScriptValue &prototype, T *)
4097 
4098     \relates QScriptEngine
4099 
4100     Registers the sequence type \c{T} in the given \a engine. This
4101     function provides conversion functions that convert between \c{T}
4102     and Qt Script \c{Array} objects. \c{T} must provide a
4103     const_iterator class and begin(), end() and push_back()
4104     functions. If \a prototype is valid, it will be set as the
4105     prototype of \c{Array} objects due to conversion from \c{T};
4106     otherwise, the standard \c{Array} prototype will be used.
4107 
4108     Returns the internal ID used by QMetaType.
4109 
4110     You need to declare the container type first with
4111     Q_DECLARE_METATYPE(). If the element type isn't a standard Qt/C++
4112     type, it must be declared using Q_DECLARE_METATYPE() as well.
4113     Example:
4114 
4115     \snippet code/src_script_qscriptengine.cpp 26
4116 
4117     \sa qScriptRegisterMetaType()
4118 */
4119 
4120 /*!
4121   Runs the garbage collector.
4122 
4123   The garbage collector will attempt to reclaim memory by locating and
4124   disposing of objects that are no longer reachable in the script
4125   environment.
4126 
4127   Normally you don't need to call this function; the garbage collector
4128   will automatically be invoked when the QScriptEngine decides that
4129   it's wise to do so (i.e. when a certain number of new objects have
4130   been created). However, you can call this function to explicitly
4131   request that garbage collection should be performed as soon as
4132   possible.
4133 
4134   \sa reportAdditionalMemoryCost()
4135 */
collectGarbage()4136 void QScriptEngine::collectGarbage()
4137 {
4138     Q_D(QScriptEngine);
4139     d->collectGarbage();
4140 }
4141 
4142 /*!
4143   \since 4.7
4144 
4145   Reports an additional memory cost of the given \a size, measured in
4146   bytes, to the garbage collector.
4147 
4148   This function can be called to indicate that a Qt Script object has
4149   memory associated with it that isn't managed by Qt Script itself.
4150   Reporting the additional cost makes it more likely that the garbage
4151   collector will be triggered.
4152 
4153   Note that if the additional memory is shared with objects outside
4154   the scripting environment, the cost should not be reported, since
4155   collecting the Qt Script object would not cause the memory to be
4156   freed anyway.
4157 
4158   Negative \a size values are ignored, i.e. this function can't be
4159   used to report that the additional memory has been deallocated.
4160 
4161   \sa collectGarbage()
4162 */
reportAdditionalMemoryCost(int size)4163 void QScriptEngine::reportAdditionalMemoryCost(int size)
4164 {
4165     Q_D(QScriptEngine);
4166     d->reportAdditionalMemoryCost(size);
4167 }
4168 
4169 /*!
4170 
4171   Sets the interval between calls to QCoreApplication::processEvents
4172   to \a interval milliseconds.
4173 
4174   While the interpreter is running, all event processing is by default
4175   blocked. This means for instance that the gui will not be updated
4176   and timers will not be fired. To allow event processing during
4177   interpreter execution one can specify the processing interval to be
4178   a positive value, indicating the number of milliseconds between each
4179   time QCoreApplication::processEvents() is called.
4180 
4181   The default value is -1, which disables event processing during
4182   interpreter execution.
4183 
4184   You can use QCoreApplication::postEvent() to post an event that
4185   performs custom processing at the next interval. For example, you
4186   could keep track of the total running time of the script and call
4187   abortEvaluation() when you detect that the script has been running
4188   for a long time without completing.
4189 
4190   \sa processEventsInterval()
4191 */
setProcessEventsInterval(int interval)4192 void QScriptEngine::setProcessEventsInterval(int interval)
4193 {
4194     Q_D(QScriptEngine);
4195     d->processEventsInterval = interval;
4196 
4197     if (interval > 0)
4198         d->globalData->timeoutChecker->setCheckInterval(interval);
4199 
4200     d->timeoutChecker()->setShouldProcessEvents(interval > 0);
4201 }
4202 
4203 /*!
4204 
4205   Returns the interval in milliseconds between calls to
4206   QCoreApplication::processEvents() while the interpreter is running.
4207 
4208   \sa setProcessEventsInterval()
4209 */
processEventsInterval() const4210 int QScriptEngine::processEventsInterval() const
4211 {
4212     Q_D(const QScriptEngine);
4213     return d->processEventsInterval;
4214 }
4215 
4216 /*!
4217   \since 4.4
4218 
4219   Returns true if this engine is currently evaluating a script,
4220   otherwise returns false.
4221 
4222   \sa evaluate(), abortEvaluation()
4223 */
isEvaluating() const4224 bool QScriptEngine::isEvaluating() const
4225 {
4226     Q_D(const QScriptEngine);
4227     return (d->currentFrame != d->globalExec()) || d->inEval;
4228 }
4229 
4230 /*!
4231   \since 4.4
4232 
4233   Aborts any script evaluation currently taking place in this engine.
4234   The given \a result is passed back as the result of the evaluation
4235   (i.e. it is returned from the call to evaluate() being aborted).
4236 
4237   If the engine isn't evaluating a script (i.e. isEvaluating() returns
4238   false), this function does nothing.
4239 
4240   Call this function if you need to abort a running script for some
4241   reason, e.g.  when you have detected that the script has been
4242   running for several seconds without completing.
4243 
4244   \sa evaluate(), isEvaluating(), setProcessEventsInterval()
4245 */
abortEvaluation(const QScriptValue & result)4246 void QScriptEngine::abortEvaluation(const QScriptValue &result)
4247 {
4248     Q_D(QScriptEngine);
4249     if (!isEvaluating())
4250         return;
4251     d->abortResult = result;
4252     d->timeoutChecker()->setShouldAbort(true);
4253     JSC::throwError(d->currentFrame, JSC::createInterruptedExecutionException(&d->currentFrame->globalData()).toObject(d->currentFrame));
4254 }
4255 
4256 #ifndef QT_NO_QOBJECT
4257 
4258 /*!
4259   \since 4.4
4260   \relates QScriptEngine
4261 
4262   Creates a connection from the \a signal in the \a sender to the
4263   given \a function. If \a receiver is an object, it will act as the
4264   `this' object when the signal handler function is invoked. Returns
4265   true if the connection succeeds; otherwise returns false.
4266 
4267   \sa qScriptDisconnect(), QScriptEngine::signalHandlerException()
4268 */
qScriptConnect(QObject * sender,const char * signal,const QScriptValue & receiver,const QScriptValue & function)4269 bool qScriptConnect(QObject *sender, const char *signal,
4270                     const QScriptValue &receiver, const QScriptValue &function)
4271 {
4272     if (!sender || !signal)
4273         return false;
4274     if (!function.isFunction())
4275         return false;
4276     if (receiver.isObject() && (receiver.engine() != function.engine()))
4277         return false;
4278     QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
4279     QScript::APIShim shim(engine);
4280     JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
4281     JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
4282     return engine->scriptConnect(sender, signal, jscReceiver, jscFunction,
4283                                  Qt::AutoConnection);
4284 }
4285 
4286 /*!
4287   \since 4.4
4288   \relates QScriptEngine
4289 
4290   Disconnects the \a signal in the \a sender from the given (\a
4291   receiver, \a function) pair. Returns true if the connection is
4292   successfully broken; otherwise returns false.
4293 
4294   \sa qScriptConnect()
4295 */
qScriptDisconnect(QObject * sender,const char * signal,const QScriptValue & receiver,const QScriptValue & function)4296 bool qScriptDisconnect(QObject *sender, const char *signal,
4297                        const QScriptValue &receiver, const QScriptValue &function)
4298 {
4299     if (!sender || !signal)
4300         return false;
4301     if (!function.isFunction())
4302         return false;
4303     if (receiver.isObject() && (receiver.engine() != function.engine()))
4304         return false;
4305     QScriptEnginePrivate *engine = QScriptEnginePrivate::get(function.engine());
4306     QScript::APIShim shim(engine);
4307     JSC::JSValue jscReceiver = engine->scriptValueToJSCValue(receiver);
4308     JSC::JSValue jscFunction = engine->scriptValueToJSCValue(function);
4309     return engine->scriptDisconnect(sender, signal, jscReceiver, jscFunction);
4310 }
4311 
4312 /*!
4313     \since 4.4
4314     \fn void QScriptEngine::signalHandlerException(const QScriptValue &exception)
4315 
4316     This signal is emitted when a script function connected to a signal causes
4317     an \a exception.
4318 
4319     \sa qScriptConnect()
4320 */
4321 
4322 QT_BEGIN_INCLUDE_NAMESPACE
4323 #include "moc_qscriptengine.cpp"
4324 QT_END_INCLUDE_NAMESPACE
4325 
4326 #endif // QT_NO_QOBJECT
4327 
4328 /*!
4329   \since 4.4
4330 
4331   Installs the given \a agent on this engine. The agent will be
4332   notified of various events pertaining to script execution. This is
4333   useful when you want to find out exactly what the engine is doing,
4334   e.g. when evaluate() is called. The agent interface is the basis of
4335   tools like debuggers and profilers.
4336 
4337   The engine maintains ownership of the \a agent.
4338 
4339   Calling this function will replace the existing agent, if any.
4340 
4341   \sa agent()
4342 */
setAgent(QScriptEngineAgent * agent)4343 void QScriptEngine::setAgent(QScriptEngineAgent *agent)
4344 {
4345     Q_D(QScriptEngine);
4346     if (agent && (agent->engine() != this)) {
4347         qWarning("QScriptEngine::setAgent(): "
4348                  "cannot set agent belonging to different engine");
4349         return;
4350     }
4351     QScript::APIShim shim(d);
4352     if (d->activeAgent)
4353         QScriptEngineAgentPrivate::get(d->activeAgent)->detach();
4354     d->activeAgent = agent;
4355     if (agent) {
4356         QScriptEngineAgentPrivate::get(agent)->attach();
4357     }
4358 }
4359 
4360 /*!
4361   \since 4.4
4362 
4363   Returns the agent currently installed on this engine, or 0 if no
4364   agent is installed.
4365 
4366   \sa setAgent()
4367 */
agent() const4368 QScriptEngineAgent *QScriptEngine::agent() const
4369 {
4370     Q_D(const QScriptEngine);
4371     return d->activeAgent;
4372 }
4373 
4374 /*!
4375   \since 4.4
4376 
4377   Returns a handle that represents the given string, \a str.
4378 
4379   QScriptString can be used to quickly look up properties, and
4380   compare property names, of script objects.
4381 
4382   \sa QScriptValue::property()
4383 */
toStringHandle(const QString & str)4384 QScriptString QScriptEngine::toStringHandle(const QString &str)
4385 {
4386     Q_D(QScriptEngine);
4387     QScript::APIShim shim(d);
4388     return d->toStringHandle(JSC::Identifier(d->currentFrame, str));
4389 }
4390 
4391 /*!
4392   \since 4.5
4393 
4394   Converts the given \a value to an object, if such a conversion is
4395   possible; otherwise returns an invalid QScriptValue. The conversion
4396   is performed according to the following table:
4397 
4398     \table
4399     \header \li Input Type \li Result
4400     \row    \li Undefined  \li An invalid QScriptValue.
4401     \row    \li Null       \li An invalid QScriptValue.
4402     \row    \li Boolean    \li A new Boolean object whose internal value is set to the value of the boolean.
4403     \row    \li Number     \li A new Number object whose internal value is set to the value of the number.
4404     \row    \li String     \li A new String object whose internal value is set to the value of the string.
4405     \row    \li Object     \li The result is the object itself (no conversion).
4406     \endtable
4407 
4408     \sa newObject()
4409 */
toObject(const QScriptValue & value)4410 QScriptValue QScriptEngine::toObject(const QScriptValue &value)
4411 {
4412     Q_D(QScriptEngine);
4413     QScript::APIShim shim(d);
4414     JSC::JSValue jscValue = d->scriptValueToJSCValue(value);
4415     if (!jscValue || jscValue.isUndefined() || jscValue.isNull())
4416         return QScriptValue();
4417     JSC::ExecState* exec = d->currentFrame;
4418     JSC::JSValue result = jscValue.toObject(exec);
4419     return d->scriptValueFromJSCValue(result);
4420 }
4421 
4422 /*!
4423   \internal
4424 
4425   Returns the object with the given \a id, or an invalid
4426   QScriptValue if there is no object with that id.
4427 
4428   \sa QScriptValue::objectId()
4429 */
objectById(qint64 id) const4430 QScriptValue QScriptEngine::objectById(qint64 id) const
4431 {
4432     Q_D(const QScriptEngine);
4433     // Assumes that the cell was not been garbage collected
4434     return const_cast<QScriptEnginePrivate*>(d)->scriptValueFromJSCValue((JSC::JSCell*)id);
4435 }
4436 
4437 /*!
4438   \since 4.5
4439   \class QScriptSyntaxCheckResult
4440   \inmodule QtScript
4441 
4442   \brief The QScriptSyntaxCheckResult class provides the result of a script syntax check.
4443 
4444   \ingroup script
4445 
4446   QScriptSyntaxCheckResult is returned by QScriptEngine::checkSyntax() to
4447   provide information about the syntactical (in)correctness of a script.
4448 */
4449 
4450 /*!
4451     \enum QScriptSyntaxCheckResult::State
4452 
4453     This enum specifies the state of a syntax check.
4454 
4455     \value Error The program contains a syntax error.
4456     \value Intermediate The program is incomplete.
4457     \value Valid The program is a syntactically correct Qt Script program.
4458 */
4459 
4460 /*!
4461   Constructs a new QScriptSyntaxCheckResult from the \a other result.
4462 */
QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult & other)4463 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(const QScriptSyntaxCheckResult &other)
4464     : d_ptr(other.d_ptr)
4465 {
4466 }
4467 
4468 /*!
4469   \internal
4470 */
QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate * d)4471 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult(QScriptSyntaxCheckResultPrivate *d)
4472     : d_ptr(d)
4473 {
4474 }
4475 
4476 /*!
4477   \internal
4478 */
QScriptSyntaxCheckResult()4479 QScriptSyntaxCheckResult::QScriptSyntaxCheckResult()
4480     : d_ptr(0)
4481 {
4482 }
4483 
4484 /*!
4485   Destroys this QScriptSyntaxCheckResult.
4486 */
~QScriptSyntaxCheckResult()4487 QScriptSyntaxCheckResult::~QScriptSyntaxCheckResult()
4488 {
4489 }
4490 
4491 /*!
4492   Returns the state of this QScriptSyntaxCheckResult.
4493 */
state() const4494 QScriptSyntaxCheckResult::State QScriptSyntaxCheckResult::state() const
4495 {
4496     Q_D(const QScriptSyntaxCheckResult);
4497     if (!d)
4498         return Valid;
4499     return d->state;
4500 }
4501 
4502 /*!
4503   Returns the error line number of this QScriptSyntaxCheckResult, or -1 if
4504   there is no error.
4505 
4506   \sa state(), errorMessage()
4507 */
errorLineNumber() const4508 int QScriptSyntaxCheckResult::errorLineNumber() const
4509 {
4510     Q_D(const QScriptSyntaxCheckResult);
4511     if (!d)
4512         return -1;
4513     return d->errorLineNumber;
4514 }
4515 
4516 /*!
4517   Returns the error column number of this QScriptSyntaxCheckResult, or -1 if
4518   there is no error.
4519 
4520   \sa state(), errorLineNumber()
4521 */
errorColumnNumber() const4522 int QScriptSyntaxCheckResult::errorColumnNumber() const
4523 {
4524     Q_D(const QScriptSyntaxCheckResult);
4525     if (!d)
4526         return -1;
4527     return d->errorColumnNumber;
4528 }
4529 
4530 /*!
4531   Returns the error message of this QScriptSyntaxCheckResult, or an empty
4532   string if there is no error.
4533 
4534   \sa state(), errorLineNumber()
4535 */
errorMessage() const4536 QString QScriptSyntaxCheckResult::errorMessage() const
4537 {
4538     Q_D(const QScriptSyntaxCheckResult);
4539     if (!d)
4540         return QString();
4541     return d->errorMessage;
4542 }
4543 
4544 /*!
4545   Assigns the \a other result to this QScriptSyntaxCheckResult, and returns a
4546   reference to this QScriptSyntaxCheckResult.
4547 */
operator =(const QScriptSyntaxCheckResult & other)4548 QScriptSyntaxCheckResult &QScriptSyntaxCheckResult::operator=(const QScriptSyntaxCheckResult &other)
4549 {
4550     d_ptr = other.d_ptr;
4551     return *this;
4552 }
4553 
4554 #ifdef QT_BUILD_INTERNAL
qt_script_isJITEnabled()4555 Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled()
4556 {
4557 #if ENABLE(JIT)
4558     return true;
4559 #else
4560     return false;
4561 #endif
4562 }
4563 #endif
4564 
4565 #ifdef Q_CC_MSVC
4566 // Try to prevent compiler from crashing.
4567 #pragma optimize("", off)
4568 #endif
4569 
4570 QT_END_NAMESPACE
4571