Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qjsengine.h"
5
6#include <private/qjsengine_p.h>
7#include <private/qjsvalue_p.h>
8#include <private/qqmlbuiltinfunctions_p.h>
9#include <private/qqmldebugconnector_p.h>
10#include <private/qqmlglobal_p.h>
11#include <private/qqmlscriptblob_p.h>
12#include <private/qqmltypeloader_p.h>
13#include <private/qv4dateobject_p.h>
14#include <private/qv4engine_p.h>
15#include <private/qv4errorobject_p.h>
16#include <private/qv4globalobject_p.h>
17#include <private/qv4mm_p.h>
18#include <private/qv4module_p.h>
19#include <private/qv4qmetaobjectwrapper_p.h>
20#include <private/qv4qobjectwrapper_p.h>
21#include <private/qv4runtime_p.h>
22#include <private/qv4script_p.h>
23#include <private/qv4stackframe_p.h>
24#include <private/qv4symbol_p.h>
25
26#include <QtQml/qjsvalue.h>
27#include <QtQml/qqmlengine.h>
28
29#include <QtCore/qcoreapplication.h>
30#include <QtCore/qdatetime.h>
31#include <QtCore/qdir.h>
32#include <QtCore/qfile.h>
33#include <QtCore/qfileinfo.h>
34#include <QtCore/qmetaobject.h>
35#include <QtCore/qmutex.h>
36#include <QtCore/qpluginloader.h>
37#include <QtCore/qstringlist.h>
38#include <QtCore/qthread.h>
39#include <QtCore/qvariant.h>
40#include <QtCore/qwaitcondition.h>
41
42Q_DECLARE_METATYPE(QList<int>)
43
44/*!
45 \since 5.0
46 \class QJSEngine
47 \reentrant
48
49 \brief The QJSEngine class provides an environment for evaluating JavaScript code.
50
51 \ingroup qtjavascript
52 \inmodule QtQml
53
54 \section1 Evaluating Scripts
55
56 Use evaluate() to evaluate script code.
57
58 \snippet code/src_script_qjsengine.cpp 0
59
60 evaluate() returns a QJSValue that holds the result of the
61 evaluation. The QJSValue class provides functions for converting
62 the result to various C++ types (e.g. QJSValue::toString()
63 and QJSValue::toNumber()).
64
65 The following code snippet shows how a script function can be
66 defined and then invoked from C++ using QJSValue::call():
67
68 \snippet code/src_script_qjsengine.cpp 1
69
70 As can be seen from the above snippets, a script is provided to the
71 engine in the form of a string. One common way of loading scripts is
72 by reading the contents of a file and passing it to evaluate():
73
74 \snippet code/src_script_qjsengine.cpp 2
75
76 Here we pass the name of the file as the second argument to
77 evaluate(). This does not affect evaluation in any way; the second
78 argument is a general-purpose string that is stored in the \c Error
79 object for debugging purposes.
80
81 For larger pieces of functionality, you may want to encapsulate
82 your code and data into modules. A module is a file that contains
83 script code, variables, etc., and uses export statements to describe
84 its interface towards the rest of the application. With the help of
85 import statements, a module can refer to functionality from other modules.
86 This allows building a scripted application from smaller connected building blocks
87 in a safe way. In contrast, the approach of using evaluate() carries the risk
88 that internal variables or functions from one evaluate() call accidentally pollute the
89 global object and affect subsequent evaluations.
90
91 The following example provides a module that can add numbers:
92
93 \code
94 export function sum(left, right)
95 {
96 return left + right
97 }
98 \endcode
99
100 This module can be loaded with QJSEngine::import() if it is saved under
101 the name \c{math.mjs}:
102
103 \code
104 QJSvalue module = myEngine.importModule("./math.mjs");
105 QJSValue sumFunction = module.property("sum");
106 QJSValue result = sumFunction.call(args);
107 \endcode
108
109 Modules can also use functionality from other modules using import
110 statements:
111
112 \code
113 import { sum } from "./math.mjs";
114 export function addTwice(left, right)
115 {
116 return sum(left, right) * 2;
117 }
118 \endcode
119
120 Modules don't have to be files. They can be values registered with
121 QJSEngine::registerModule():
122
123 \code
124 import version from "version";
125
126 export function getVersion()
127 {
128 return version;
129 }
130 \endcode
131
132 \code
133 QJSValue version(610);
134 myEngine.registerModule("version", version);
135 QJSValue module = myEngine.importModule("./myprint.mjs");
136 QJSValue getVersion = module.property("getVersion");
137 QJSValue result = getVersion.call();
138 \endcode
139
140 Named exports are supported, but because they are treated as members of an
141 object, the default export must be an ECMAScript object. Most of the newXYZ
142 functions in QJSValue will return an object.
143
144 \code
145 QJSValue name("Qt6");
146 QJSValue obj = myEngine.newObject();
147 obj.setProperty("name", name);
148 myEngine.registerModule("info", obj);
149 \endcode
150
151 \code
152 import { name } from "info";
153
154 export function getName()
155 {
156 return name;
157 }
158 \endcode
159
160 \section1 Engine Configuration
161
162 The globalObject() function returns the \b {Global Object}
163 associated with the script engine. Properties of the Global Object
164 are accessible from any script code (i.e. they are global
165 variables). Typically, before evaluating "user" scripts, you will
166 want to configure a script engine by adding one or more properties
167 to the Global Object:
168
169 \snippet code/src_script_qjsengine.cpp 3
170
171 Adding custom properties to the scripting environment is one of the
172 standard means of providing a scripting API that is specific to your
173 application. Usually these custom properties are objects created by
174 the newQObject() or newObject() functions.
175
176 \section1 Script Exceptions
177
178 evaluate() can throw a script exception (e.g. due to a syntax
179 error). If it does, then evaluate() returns the value that was thrown
180 (typically an \c{Error} object). Use \l QJSValue::isError() to check
181 for exceptions.
182
183 For detailed information about the error, use \l QJSValue::toString() to
184 obtain an error message, and use \l QJSValue::property() to query the
185 properties of the \c Error object. The following properties are available:
186
187 \list
188 \li \c name
189 \li \c message
190 \li \c fileName
191 \li \c lineNumber
192 \li \c stack
193 \endlist
194
195 \snippet code/src_script_qjsengine.cpp 4
196
197 \section1 Script Object Creation
198
199 Use newObject() to create a JavaScript object; this is the
200 C++ equivalent of the script statement \c{new Object()}. You can use
201 the object-specific functionality in QJSValue to manipulate the
202 script object (e.g. QJSValue::setProperty()). Similarly, use
203 newArray() to create a JavaScript array object.
204
205 \section1 QObject Integration
206
207 Use newQObject() to wrap a QObject (or subclass)
208 pointer. newQObject() returns a proxy script object; properties,
209 children, and signals and slots of the QObject are available as
210 properties of the proxy object. No binding code is needed because it
211 is done dynamically using the Qt meta object system.
212
213 \snippet code/src_script_qjsengine.cpp 5
214
215 Use newQMetaObject() to wrap a QMetaObject; this gives you a
216 "script representation" of a QObject-based class. newQMetaObject()
217 returns a proxy script object; enum values of the class are available
218 as properties of the proxy object.
219
220 Constructors exposed to the meta-object system (using Q_INVOKABLE) can be
221 called from the script to create a new QObject instance with
222 JavaScriptOwnership. For example, given the following class definition:
223
224 \snippet code/src_script_qjsengine.cpp 7
225
226 The \c staticMetaObject for the class can be exposed to JavaScript like so:
227
228 \snippet code/src_script_qjsengine.cpp 8
229
230 Instances of the class can then be created in JavaScript:
231
232 \snippet code/src_script_qjsengine.cpp 9
233
234 \note Currently only classes using the Q_OBJECT macro are supported; it is
235 not possible to expose the \c staticMetaObject of a Q_GADGET class to
236 JavaScript.
237
238 \section2 Dynamic QObject Properties
239
240 Dynamic QObject properties are not supported. For example, the following code
241 will not work:
242
243 \snippet code/src_script_qjsengine.cpp 6
244
245 \section1 Extensions
246
247 QJSEngine provides a compliant ECMAScript implementation. By default,
248 familiar utilities like logging are not available, but they can be
249 installed via the \l installExtensions() function.
250
251 \sa QJSValue, {Making Applications Scriptable},
252 {List of JavaScript Objects and Functions}
253
254*/
255
256/*!
257 \enum QJSEngine::Extension
258
259 This enum is used to specify extensions to be installed via
260 \l installExtensions().
261
262 \value TranslationExtension Indicates that translation functions (\c qsTr(),
263 for example) should be installed. This also installs the Qt.uiLanguage property.
264
265 \value ConsoleExtension Indicates that console functions (\c console.log(),
266 for example) should be installed.
267
268 \value GarbageCollectionExtension Indicates that garbage collection
269 functions (\c gc(), for example) should be installed.
270
271 \value AllExtensions Indicates that all extension should be installed.
272
273 \b TranslationExtension
274
275 The relation between script translation functions and C++ translation
276 functions is described in the following table:
277
278 \table
279 \header \li Script Function \li Corresponding C++ Function
280 \row \li qsTr() \li QObject::tr()
281 \row \li QT_TR_NOOP() \li QT_TR_NOOP()
282 \row \li qsTranslate() \li QCoreApplication::translate()
283 \row \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP()
284 \row \li qsTrId() \li qtTrId()
285 \row \li QT_TRID_NOOP() \li QT_TRID_NOOP()
286 \endtable
287
288 This flag also adds an \c arg() function to the string prototype.
289
290 For more information, see the \l {Internationalization with Qt}
291 documentation.
292
293 \b ConsoleExtension
294
295 The \l {Console API}{console} object implements a subset of the
296 \l {https://developer.mozilla.org/en-US/docs/Web/API/Console}{Console API},
297 which provides familiar logging functions, such as \c console.log().
298
299 The list of functions added is as follows:
300
301 \list
302 \li \c console.assert()
303 \li \c console.debug()
304 \li \c console.exception()
305 \li \c console.info()
306 \li \c console.log() (equivalent to \c console.debug())
307 \li \c console.error()
308 \li \c console.time()
309 \li \c console.timeEnd()
310 \li \c console.trace()
311 \li \c console.count()
312 \li \c console.warn()
313 \li \c {print()} (equivalent to \c console.debug())
314 \endlist
315
316 For more information, see the \l {Console API} documentation.
317
318 \b GarbageCollectionExtension
319
320 The \c gc() function is equivalent to calling \l collectGarbage().
321*/
322
323QT_BEGIN_NAMESPACE
324
325static void checkForApplicationInstance()
326{
327 if (!QCoreApplication::instance())
328 qFatal("QJSEngine: Must construct a QCoreApplication before a QJSEngine");
329}
330
331/*!
332 Constructs a QJSEngine object.
333
334 The globalObject() is initialized to have properties as described in
335 \l{ECMA-262}, Section 15.1.
336*/
337QJSEngine::QJSEngine()
338 : QJSEngine(nullptr)
339{
340}
341
342/*!
343 Constructs a QJSEngine object with the given \a parent.
344
345 The globalObject() is initialized to have properties as described in
346 \l{ECMA-262}, Section 15.1.
347*/
348
349QJSEngine::QJSEngine(QObject *parent)
350 : QJSEngine(*new QJSEnginePrivate, parent)
351{
352 QJSEnginePrivate::addToDebugServer(this);
353}
354
355/*!
356 \internal
357*/
358QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
359 : QObject(dd, parent)
360{
361 dd.v4Engine = std::make_unique<QV4::ExecutionEngine>(this);
362 m_v4Engine = dd.v4Engine.get();
363 checkForApplicationInstance();
364}
365
366/*!
367 Destroys this QJSEngine.
368
369 Garbage is not collected from the persistent JS heap during QJSEngine
370 destruction. If you need all memory freed, call collectGarbage() manually
371 right before destroying the QJSEngine.
372*/
373QJSEngine::~QJSEngine()
374{
375 m_v4Engine->inShutdown = true;
376 QJSEnginePrivate::removeFromDebugServer(this);
377 m_v4Engine->publicEngine = nullptr;
378}
379
380/*!
381 \fn QV4::ExecutionEngine *QJSEngine::handle() const
382 \internal
383*/
384
385/*!
386 Runs the garbage collector.
387
388 The garbage collector will attempt to reclaim memory by locating and disposing of objects that are
389 no longer reachable in the script environment.
390
391 Normally you don't need to call this function; the garbage collector will automatically be invoked
392 when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects
393 have been created). However, you can call this function to explicitly request that garbage
394 collection should be performed as soon as possible.
395
396
397 \sa {Garbage Collection}
398 \sa {Qt::}{gc()}
399 */
400void QJSEngine::collectGarbage()
401{
402 m_v4Engine->memoryManager->runFullGC();
403}
404
405/*!
406 \since 5.6
407
408 Installs JavaScript \a extensions to add functionality that is not
409 available in a standard ECMAScript implementation.
410
411 The extensions are installed on the given \a object, or on the
412 \l {globalObject()}{Global Object} if no object is specified.
413
414 Several extensions can be installed at once by \c {OR}-ing the enum values:
415
416 \code
417 installExtensions(QJSEngine::TranslationExtension | QJSEngine::ConsoleExtension);
418 \endcode
419
420 \sa Extension
421*/
422void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSValue &object)
423{
424 QV4::ExecutionEngine *otherEngine = QJSValuePrivate::engine(&object);
425 if (otherEngine && otherEngine != m_v4Engine) {
426 qWarning("QJSEngine: Trying to install extensions from a different engine");
427 return;
428 }
429
430 QV4::Scope scope(m_v4Engine);
431 QV4::ScopedObject obj(scope, QJSValuePrivate::asReturnedValue(&object));
432 if (!obj)
433 obj = scope.engine->globalObject;
434
435 QV4::GlobalExtensions::init(obj, extensions);
436}
437
438/*!
439 \since 5.14
440 Interrupts or re-enables JavaScript execution.
441
442 If \a interrupted is \c true, any JavaScript executed by this engine
443 immediately aborts and returns an error object until this function is
444 called again with a value of \c false for \a interrupted.
445
446 This function is thread safe. You may call it from a different thread
447 in order to interrupt, for example, an infinite loop in JavaScript.
448*/
449void QJSEngine::setInterrupted(bool interrupted)
450{
451 m_v4Engine->isInterrupted.storeRelaxed(interrupted);
452}
453
454/*!
455 \since 5.14
456 Returns whether JavaScript execution is currently interrupted.
457
458 \sa setInterrupted()
459*/
460bool QJSEngine::isInterrupted() const
461{
462 return m_v4Engine->isInterrupted.loadRelaxed();
463}
464
465static QUrl urlForFileName(const QString &fileName)
466{
467 if (!fileName.startsWith(QLatin1Char(':')))
468 return QUrl::fromLocalFile(fileName);
469
470 QUrl url;
471 url.setPath(fileName.mid(1));
472 url.setScheme(QLatin1String("qrc"));
473 return url;
474}
475
476/*!
477 Evaluates \a program, using \a lineNumber as the base line number,
478 and returns the result of the evaluation.
479
480 The script code will be evaluated in the context of the global object.
481
482 \note If you need to evaluate inside a QML context, use \l QQmlExpression
483 instead.
484
485 The evaluation of \a program can cause an \l{Script Exceptions}{exception} in the
486 engine; in this case the return value will be the exception
487 that was thrown (typically an \c{Error} object; see
488 QJSValue::isError()).
489
490 \a lineNumber is used to specify a starting line number for \a
491 program; line number information reported by the engine that pertains
492 to this evaluation will be based on this argument. For example, if
493 \a program consists of two lines of code, and the statement on the
494 second line causes a script exception, the exception line number
495 would be \a lineNumber plus one. When no starting line number is
496 specified, line numbers will be 1-based.
497
498 \a fileName is used for error reporting. For example, in error objects
499 the file name is accessible through the "fileName" property if it is
500 provided with this function.
501
502 \a exceptionStackTrace is used to report whether an uncaught exception was
503 thrown. If you pass a non-null pointer to a QStringList to it, it will set
504 it to list of "stackframe messages" if the script threw an unhandled
505 exception, or an empty list otherwise. A stackframe message has the format
506 function name:line number:column:file name
507 \note In some cases, e.g. for native functions, function name and file name
508 can be empty and line number and column can be -1.
509
510 \note If an exception was thrown and the exception value is not an
511 Error instance (i.e., QJSValue::isError() returns \c false), the
512 exception value will still be returned. Use \c exceptionStackTrace->isEmpty()
513 to distinguish whether the value was a normal or an exceptional return
514 value.
515
516 \sa QQmlExpression::evaluate
517*/
518QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber, QStringList *exceptionStackTrace)
519{
520 QV4::ExecutionEngine *v4 = m_v4Engine;
521 QV4::Scope scope(v4);
522 QV4::ScopedValue result(scope);
523
524 QV4::Script script(v4->rootContext(), QV4::Compiler::ContextType::Global, program, urlForFileName(fileName).toString(), lineNumber);
525 script.setStrictMode(false);
526 if (v4->currentStackFrame)
527 script.setStrictMode(v4->currentStackFrame->v4Function->isStrict());
528 else if (v4->globalCode)
529 script.setStrictMode(v4->globalCode->isStrict());
530 script.setInheritContext();
531 script.parse();
532 if (!scope.hasException())
533 result = script.run();
534 if (exceptionStackTrace)
535 exceptionStackTrace->clear();
536 if (scope.hasException()) {
537 QV4::StackTrace trace;
538 result = v4->catchException(&trace);
539 if (exceptionStackTrace) {
540 for (auto &&frame: trace)
541 exceptionStackTrace->push_back(QLatin1StringView("%1:%2:%3:%4").arg(
542 frame.function,
543 QString::number(qAbs(frame.line)),
544 QString::number(frame.column),
545 frame.source)
546 );
547 }
548 }
549 if (v4->isInterrupted.loadRelaxed())
550 result = v4->newErrorObject(QStringLiteral("Interrupted"));
551
552 if (const auto cu = script.compilationUnit())
553 v4->trimCompilationUnitsForUrl(cu->finalUrl());
554 return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
555}
556
557/*!
558 Imports the module located at \a fileName and returns a module namespace object that
559 contains all exported variables, constants and functions as properties.
560
561 If this is the first time the module is imported in the engine, the file is loaded
562 from the specified location in either the local file system or the Qt resource system
563 and evaluated as an ECMAScript module. The file is expected to be encoded in UTF-8 text.
564
565 Subsequent imports of the same module will return the previously imported instance. Modules
566 are singletons and remain around until the engine is destroyed.
567
568 The specified \a fileName will internally be normalized using \l QFileInfo::canonicalFilePath().
569 That means that multiple imports of the same file on disk using different relative paths will
570 load the file only once.
571
572 \note If an exception is thrown during the loading of the module, the return value
573 will be the exception (typically an \c{Error} object; see QJSValue::isError()).
574
575 \sa registerModule()
576
577 \since 5.12
578 */
579QJSValue QJSEngine::importModule(const QString &fileName)
580{
581 QUrl url = urlForFileName(QFileInfo(fileName).canonicalFilePath());
582 if (!fileName.endsWith(QLatin1String(".mjs")))
583 url.setFragment(QLatin1String("module"));
584
585 QQmlRefPointer<QQmlScriptBlob> scriptBlob = m_v4Engine->typeLoader()->getScript(url);
586
587 if (scriptBlob->isError()) {
588 const QList<QQmlError> errors = scriptBlob->errors();
589 switch (errors.length()) {
590 case 0:
591 Q_UNREACHABLE_RETURN(QJSValue());
592 case 1: {
593 const QQmlError &error = errors[0];
594 m_v4Engine->throwSyntaxError(
595 error.description(), error.url().toString(), error.line(), error.column());
596 return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
597 }
598 default: {
599 QString errorString = QStringLiteral("Importing module failed:");
600 for (const QQmlError &error : errors) {
601 errorString += QLatin1String("\n ");
602 errorString += error.toString();
603 }
604 m_v4Engine->throwSyntaxError(errorString);
605 return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
606 }
607 }
608 }
609
610 // We've just created the URL from a local file. So it has to be synchronous.
611 Q_ASSERT(scriptBlob->isComplete());
612
613 const auto module
614 = m_v4Engine->executableCompilationUnit(scriptBlob->scriptData()->compilationUnit());
615
616 // If there is neither a native nor a compiled module, we should have seen an exception
617 Q_ASSERT(module);
618
619 QV4::Scope scope(m_v4Engine);
620 QV4::ScopedValue value(scope, module->value());
621 if (!value->isEmpty())
622 return QJSValuePrivate::fromReturnedValue(value->asReturnedValue());
623
624 QV4::Scoped<QV4::Module> moduleNamespace(scope, module->instantiate());
625 if (m_v4Engine->hasException)
626 return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
627
628 module->evaluate();
629 if (m_v4Engine->isInterrupted.loadRelaxed()) {
630 return QJSValuePrivate::fromReturnedValue(
631 m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
632 }
633
634 return QJSValuePrivate::fromReturnedValue(moduleNamespace->asReturnedValue());
635}
636
637/*!
638 Registers a QJSValue to serve as a module. After this function is called,
639 all modules that import \a moduleName will import the value of \a value
640 instead of loading \a moduleName from the filesystem.
641
642 Any valid QJSValue can be registered, but named exports (i.e.
643 \c {import { name } from "info"} are treated as members of an object, so
644 the default export must be created with one of the newXYZ methods of
645 QJSEngine.
646
647 Because this allows modules that do not exist on the filesystem to be imported,
648 scripting applications can use this to provide built-in modules, similar to
649 Node.js.
650
651 Returns \c true on success, \c false otherwise.
652
653 \note The QJSValue \a value is not called or read until it is used by another module.
654 This means that there is no code to evaluate, so no errors will be seen until
655 another module throws an exception while trying to load this module.
656
657 \warning Attempting to access a named export from a QJSValue that is not an
658 object will trigger a \l{Script Exceptions}{exception}.
659
660 \sa importModule()
661 */
662bool QJSEngine::registerModule(const QString &moduleName, const QJSValue &value)
663{
664 QV4::Scope scope(m_v4Engine);
665 QV4::ScopedValue v4Value(scope, QJSValuePrivate::asReturnedValue(&value));
666 m_v4Engine->registerNativeModule(QUrl(moduleName), v4Value);
667 if (m_v4Engine->hasException)
668 return false;
669 return true;
670}
671
672/*!
673 Creates a JavaScript object of class Object.
674
675 The prototype of the created object will be the Object
676 prototype object.
677
678 \sa newArray(), QJSValue::setProperty()
679*/
680QJSValue QJSEngine::newObject()
681{
682 QV4::Scope scope(m_v4Engine);
683 QV4::ScopedValue v(scope, m_v4Engine->newObject());
684 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
685}
686
687/*!
688 \since 6.2
689
690 Creates a JavaScript object of class Symbol, with value \a name.
691
692 The prototype of the created object will be the Symbol prototype object.
693
694 \sa newObject()
695*/
696QJSValue QJSEngine::newSymbol(const QString &name)
697{
698 QV4::Scope scope(m_v4Engine);
699 QV4::ScopedValue v(scope, QV4::Symbol::create(m_v4Engine, u'@' + name));
700 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
701}
702
703/*!
704 \since 5.12
705
706 Creates a JavaScript object of class Error, with \a message as the error
707 message.
708
709 The prototype of the created object will be \a errorType.
710
711 \sa newObject(), throwError(), QJSValue::isError()
712*/
713QJSValue QJSEngine::newErrorObject(QJSValue::ErrorType errorType, const QString &message)
714{
715 QV4::Scope scope(m_v4Engine);
716 QV4::ScopedObject error(scope);
717 switch (errorType) {
718 case QJSValue::RangeError:
719 error = m_v4Engine->newRangeErrorObject(message);
720 break;
721 case QJSValue::SyntaxError:
722 error = m_v4Engine->newSyntaxErrorObject(message);
723 break;
724 case QJSValue::TypeError:
725 error = m_v4Engine->newTypeErrorObject(message);
726 break;
727 case QJSValue::URIError:
728 error = m_v4Engine->newURIErrorObject(message);
729 break;
730 case QJSValue::ReferenceError:
731 error = m_v4Engine->newReferenceErrorObject(message);
732 break;
733 case QJSValue::EvalError:
734 error = m_v4Engine->newEvalErrorObject(message);
735 break;
736 case QJSValue::GenericError:
737 error = m_v4Engine->newErrorObject(message);
738 break;
739 case QJSValue::NoError:
740 return QJSValue::UndefinedValue;
741 }
742 return QJSValuePrivate::fromReturnedValue(error->asReturnedValue());
743}
744
745/*!
746 Creates a JavaScript object of class Array with the given \a length.
747
748 \sa newObject()
749*/
750QJSValue QJSEngine::newArray(uint length)
751{
752 QV4::Scope scope(m_v4Engine);
753 QV4::ScopedArrayObject array(scope, m_v4Engine->newArrayObject());
754 if (length < 0x1000)
755 array->arrayReserve(length);
756 array->setArrayLengthUnchecked(length);
757 return QJSValuePrivate::fromReturnedValue(array.asReturnedValue());
758}
759
760/*!
761 Creates a JavaScript object that wraps the given QObject \a
762 object, using JavaScriptOwnership.
763
764 Signals and slots, properties and children of \a object are
765 available as properties of the created QJSValue.
766
767 If \a object is a null pointer, this function returns a null value.
768
769 If a default prototype has been registered for the \a object's class
770 (or its superclass, recursively), the prototype of the new script
771 object will be set to be that default prototype.
772
773 If the given \a object is deleted outside of the engine's control, any
774 attempt to access the deleted QObject's members through the JavaScript
775 wrapper object (either by script code or C++) will result in a
776 \l{Script Exceptions}{script exception}.
777
778 \sa QJSValue::toQObject()
779*/
780QJSValue QJSEngine::newQObject(QObject *object)
781{
782 QV4::ExecutionEngine *v4 = m_v4Engine;
783 QV4::Scope scope(v4);
784 if (object) {
785 QQmlData *ddata = QQmlData::get(object, true);
786 if (!ddata || !ddata->explicitIndestructibleSet)
787 QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
788 }
789 QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(v4, object));
790 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
791}
792
793/*!
794 \since 5.8
795
796 Creates a JavaScript object that wraps the given QMetaObject
797 The \a metaObject must outlive the script engine. It is recommended to only
798 use this method with static metaobjects.
799
800
801 When called as a constructor, a new instance of the class will be created.
802 Only constructors exposed by Q_INVOKABLE will be visible from the script engine.
803
804 \sa newQObject(), {QObject Integration}
805*/
806
807QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
808 QV4::ExecutionEngine *v4 = m_v4Engine;
809 QV4::Scope scope(v4);
810 QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
811 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
812}
813
814/*! \fn template <typename T> QJSValue QJSEngine::newQMetaObject()
815
816 \since 5.8
817 Creates a JavaScript object that wraps the static QMetaObject associated
818 with class \c{T}.
819
820 \sa newQObject(), {QObject Integration}
821*/
822
823
824/*!
825 Returns this engine's Global Object.
826
827 By default, the Global Object contains the built-in objects that are
828 part of \l{ECMA-262}, such as Math, Date and String. Additionally,
829 you can set properties of the Global Object to make your own
830 extensions available to all script code. Non-local variables in
831 script code will be created as properties of the Global Object, as
832 well as local variables in global code.
833*/
834QJSValue QJSEngine::globalObject() const
835{
836 QV4::Scope scope(m_v4Engine);
837 QV4::ScopedValue v(scope, m_v4Engine->globalObject);
838 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
839}
840
841QJSPrimitiveValue QJSEngine::createPrimitive(QMetaType type, const void *ptr)
842{
843 QV4::Scope scope(m_v4Engine);
844 QV4::ScopedValue v(scope, m_v4Engine->metaTypeToJS(type, ptr));
845 return QV4::ExecutionEngine::createPrimitive(v);
846}
847
848QJSManagedValue QJSEngine::createManaged(QMetaType type, const void *ptr)
849{
850 QJSManagedValue result(m_v4Engine);
851 *result.d = m_v4Engine->metaTypeToJS(type, ptr);
852 return result;
853}
854
855/*!
856 * \internal
857 * used by QJSEngine::toScriptValue
858 */
859QJSValue QJSEngine::create(QMetaType type, const void *ptr)
860{
861 QV4::Scope scope(m_v4Engine);
862 QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(type, ptr));
863 return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
864}
865
866bool QJSEngine::convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr)
867{
868 switch (value.type()) {
869 case QJSPrimitiveValue::Undefined:
870 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::undefinedValue(), type, ptr);
871 case QJSPrimitiveValue::Null:
872 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::nullValue(), type, ptr);
873 case QJSPrimitiveValue::Boolean:
874 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromBoolean(value.toBoolean()), type, ptr);
875 case QJSPrimitiveValue::Integer:
876 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromInt32(value.toInteger()), type, ptr);
877 case QJSPrimitiveValue::Double:
878 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromDouble(value.toDouble()), type, ptr);
879 case QJSPrimitiveValue::String:
880 return convertString(value.toString(), type, ptr);
881 }
882
883 Q_UNREACHABLE_RETURN(false);
884}
885
886bool QJSEngine::convertManaged(const QJSManagedValue &value, int type, void *ptr)
887{
888 return convertManaged(value, QMetaType(type), ptr);
889}
890
891bool QJSEngine::convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr)
892{
893 return QV4::ExecutionEngine::metaTypeFromJS(*value.d, type, ptr);
894}
895
896bool QJSEngine::convertString(const QString &string, QMetaType metaType, void *ptr)
897{
898 // have a string based value without engine. Do conversion manually
899 if (metaType == QMetaType::fromType<bool>()) {
900 *reinterpret_cast<bool*>(ptr) = string.size() != 0;
901 return true;
902 }
903 if (metaType == QMetaType::fromType<QString>()) {
904 *reinterpret_cast<QString*>(ptr) = string;
905 return true;
906 }
907 if (metaType == QMetaType::fromType<QUrl>()) {
908 *reinterpret_cast<QUrl *>(ptr) = QUrl(string);
909 return true;
910 }
911
912 double d = QV4::RuntimeHelpers::stringToNumber(string);
913 switch (metaType.id()) {
914 case QMetaType::Int:
915 *reinterpret_cast<int*>(ptr) = QV4::Value::toInt32(d);
916 return true;
917 case QMetaType::UInt:
918 *reinterpret_cast<uint*>(ptr) = QV4::Value::toUInt32(d);
919 return true;
920 case QMetaType::Long:
921 *reinterpret_cast<long*>(ptr) = QV4::Value::toInteger(d);
922 return true;
923 case QMetaType::ULong:
924 *reinterpret_cast<ulong*>(ptr) = QV4::Value::toInteger(d);
925 return true;
926 case QMetaType::LongLong:
927 *reinterpret_cast<qlonglong*>(ptr) = QV4::Value::toInteger(d);
928 return true;
929 case QMetaType::ULongLong:
930 *reinterpret_cast<qulonglong*>(ptr) = QV4::Value::toInteger(d);
931 return true;
932 case QMetaType::Double:
933 *reinterpret_cast<double*>(ptr) = d;
934 return true;
935 case QMetaType::Float:
936 *reinterpret_cast<float*>(ptr) = d;
937 return true;
938 case QMetaType::Short:
939 *reinterpret_cast<short*>(ptr) = QV4::Value::toInt32(d);
940 return true;
941 case QMetaType::UShort:
942 *reinterpret_cast<unsigned short*>(ptr) = QV4::Value::toUInt32(d);
943 return true;
944 case QMetaType::Char:
945 *reinterpret_cast<char*>(ptr) = QV4::Value::toInt32(d);
946 return true;
947 case QMetaType::UChar:
948 *reinterpret_cast<unsigned char*>(ptr) = QV4::Value::toUInt32(d);
949 return true;
950 case QMetaType::QChar:
951 *reinterpret_cast<QChar*>(ptr) = QChar(QV4::Value::toUInt32(d));
952 return true;
953 case QMetaType::Char16:
954 *reinterpret_cast<char16_t *>(ptr) = QV4::Value::toUInt32(d);
955 return true;
956 default:
957 return false;
958 }
959}
960
961/*!
962 \internal
963 convert \a value to \a type, store the result in \a ptr
964*/
965bool QJSEngine::convertV2(const QJSValue &value, QMetaType metaType, void *ptr)
966{
967 if (const QString *string = QJSValuePrivate::asQString(&value))
968 return convertString(*string, metaType, ptr);
969
970 // Does not need scoping since QJSValue still holds on to the value.
971 return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&value)),
972 metaType, ptr);
973}
974
975bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *ptr)
976{
977 // TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
978 // duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
979 QV4::Scope scope(handle());
980 QV4::ScopedValue scoped(scope, scope.engine->fromVariant(value));
981 return QV4::ExecutionEngine::metaTypeFromJS(scoped, metaType, ptr);
982}
983
984bool QJSEngine::convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to)
985{
986 // TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
987 // duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
988 QV4::Scope scope(handle());
989 QV4::ScopedValue scoped(scope, scope.engine->fromData(fromType, from));
990 return QV4::ExecutionEngine::metaTypeFromJS(scoped, toType, to);
991}
992
993QString QJSEngine::convertQObjectToString(QObject *object)
994{
995 return QV4::QObjectWrapper::objectToString(
996 handle(), object ? object->metaObject() : nullptr, object);
997}
998
999QString QJSEngine::convertDateTimeToString(const QDateTime &dateTime)
1000{
1001 return QV4::DateObject::dateTimeToString(dateTime, handle());
1002}
1003
1004double QJSEngine::convertDateTimeToNumber(const QDateTime &dateTime)
1005{
1006 return QV4::DateObject::dateTimeToNumber(dateTime);
1007}
1008
1009QDate QJSEngine::convertDateTimeToDate(const QDateTime &dateTime)
1010{
1011 return QV4::DateObject::dateTimeToDate(dateTime);
1012}
1013
1014/*! \fn template <typename T> QJSValue QJSEngine::toScriptValue(const T &value)
1015
1016 Creates a QJSValue with the given \a value.
1017
1018 \sa fromScriptValue(), coerceValue()
1019*/
1020
1021/*! \fn template <typename T> QJSManagedValue QJSEngine::toManagedValue(const T &value)
1022
1023 Creates a QJSManagedValue with the given \a value.
1024
1025 \sa fromManagedValue(), coerceValue()
1026*/
1027
1028/*! \fn template <typename T> QJSPrimitiveValue QJSEngine::toPrimitiveValue(const T &value)
1029
1030 Creates a QJSPrimitiveValue with the given \a value.
1031
1032 Since QJSPrimitiveValue can only hold int, bool, double, QString, and the
1033 equivalents of JavaScript \c null and \c undefined, the value will be
1034 coerced aggressively if you pass any other type.
1035
1036 \sa fromPrimitiveValue(), coerceValue()
1037*/
1038
1039/*! \fn template <typename T> T QJSEngine::fromScriptValue(const QJSValue &value)
1040
1041 Returns the given \a value converted to the template type \c{T}.
1042
1043 \sa toScriptValue(), coerceValue()
1044*/
1045
1046/*! \fn template <typename T> T QJSEngine::fromManagedValue(const QJSManagedValue &value)
1047
1048 Returns the given \a value converted to the template type \c{T}.
1049
1050 \sa toManagedValue(), coerceValue()
1051*/
1052
1053/*! \fn template <typename T> T QJSEngine::fromPrimitiveValue(const QJSPrimitiveValue &value)
1054
1055 Returns the given \a value converted to the template type \c{T}.
1056
1057 Since QJSPrimitiveValue can only hold int, bool, double, QString, and the
1058 equivalents of JavaScript \c null and \c undefined, the value will be
1059 coerced aggressively if you request any other type.
1060
1061 \sa toPrimitiveValue(), coerceValue()
1062*/
1063
1064/*! \fn template <typename T> T QJSEngine::fromVariant(const QVariant &value)
1065
1066 Returns the given \a value converted to the template type \c{T}.
1067 The conversion is done in JavaScript semantics. Those differ from
1068 qvariant_cast's semantics. There are a number of implicit
1069 conversions between JavaScript-equivalent types that are not
1070 performed by qvariant_cast by default.
1071
1072 \sa coerceValue(), fromScriptValue(), {QVariant::}{qvariant_cast()}
1073*/
1074
1075/*! \fn template <typename From, typename To> T QJSEngine::coerceValue(const From &from)
1076
1077 Returns the given \a from converted to the template type \c{To}.
1078 The conversion is done in JavaScript semantics. Those differ from
1079 qvariant_cast's semantics. There are a number of implicit
1080 conversions between JavaScript-equivalent types that are not
1081 performed by qvariant_cast by default. This method is a generalization of
1082 all the other conversion methods in this class.
1083
1084 \sa fromVariant(), {QVariant::}{qvariant_cast()}, fromScriptValue(), toScriptValue()
1085*/
1086
1087/*!
1088 Throws a run-time error (exception) with the given \a message.
1089
1090 This method is the C++ counterpart of a \c throw() expression in
1091 JavaScript. It enables C++ code to report run-time errors to QJSEngine.
1092 Therefore it should only be called from C++ code that was invoked by a
1093 JavaScript function through QJSEngine.
1094
1095 When returning from C++, the engine will interrupt the normal flow of
1096 execution and call the next pre-registered exception handler with
1097 an error object that contains the given \a message. The error object
1098 will point to the location of the top-most context on the JavaScript
1099 caller stack; specifically, it will have properties \c lineNumber,
1100 \c fileName and \c stack. These properties are described in
1101 \l{Script Exceptions}.
1102
1103 In the following example a C++ method in \e FileAccess.cpp throws an error
1104 in \e qmlFile.qml at the position where \c readFileAsText() is called:
1105
1106 \code
1107 // qmlFile.qml
1108 function someFunction() {
1109 ...
1110 var text = FileAccess.readFileAsText("/path/to/file.txt");
1111 }
1112 \endcode
1113
1114 \code
1115 // FileAccess.cpp
1116 // Assuming that FileAccess is a QObject-derived class that has been
1117 // registered as a singleton type and provides an invokable method
1118 // readFileAsText()
1119
1120 QJSValue FileAccess::readFileAsText(const QString & filePath) {
1121 QFile file(filePath);
1122
1123 if (!file.open(QIODevice::ReadOnly)) {
1124 jsEngine->throwError(file.errorString());
1125 return QString();
1126 }
1127
1128 ...
1129 return content;
1130 }
1131 \endcode
1132
1133 It is also possible to catch the thrown error in JavaScript:
1134 \code
1135 // qmlFile.qml
1136 function someFunction() {
1137 ...
1138 var text;
1139 try {
1140 text = FileAccess.readFileAsText("/path/to/file.txt");
1141 } catch (error) {
1142 console.warn("In " + error.fileName + ":" + "error.lineNumber" +
1143 ": " + error.message);
1144 }
1145 }
1146 \endcode
1147
1148 If you need a more specific run-time error to describe an exception, you can use the
1149 \l {QJSEngine::}{throwError(QJSValue::ErrorType errorType, const QString &message)}
1150 overload.
1151
1152 \since Qt 5.12
1153 \sa {Script Exceptions}
1154*/
1155void QJSEngine::throwError(const QString &message)
1156{
1157 m_v4Engine->throwError(message);
1158}
1159
1160/*!
1161 \overload throwError()
1162
1163 Throws a run-time error (exception) with the given \a errorType and
1164 \a message.
1165
1166 \code
1167 // Assuming that DataEntry is a QObject-derived class that has been
1168 // registered as a singleton type and provides an invokable method
1169 // setAge().
1170
1171 void DataEntry::setAge(int age) {
1172 if (age < 0 || age > 200) {
1173 jsEngine->throwError(QJSValue::RangeError,
1174 "Age must be between 0 and 200");
1175 }
1176 ...
1177 }
1178 \endcode
1179
1180 \since Qt 5.12
1181 \sa {Script Exceptions}, newErrorObject()
1182*/
1183void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message)
1184{
1185 QV4::Scope scope(m_v4Engine);
1186 QJSValue error = newErrorObject(errorType, message);
1187 QV4::ScopedObject e(scope, QJSValuePrivate::asReturnedValue(&error));
1188 if (!e)
1189 return;
1190 m_v4Engine->throwError(e);
1191}
1192
1193/*!
1194 \overload throwError()
1195
1196 Throws a pre-constructed run-time \a error (exception). This way you can
1197 use \l newErrorObject() to create the error and customize it as necessary.
1198
1199 \since 6.1
1200 \sa {Script Exceptions}, newErrorObject()
1201*/
1202void QJSEngine::throwError(const QJSValue &error)
1203{
1204 // safe, QJSValue holds a persistent reference
1205 m_v4Engine->throwError(
1206 QV4::Value::fromReturnedValue(
1207 QJSValuePrivate::convertToReturnedValue(m_v4Engine, error)));
1208}
1209
1210/*!
1211 * Returns \c true if the last JavaScript execution resulted in an exception or
1212 * if throwError() was called. Otherwise returns \c false. Mind that evaluate()
1213 * catches any exceptions thrown in the evaluated code.
1214 *
1215 * \since Qt 6.1
1216 */
1217bool QJSEngine::hasError() const
1218{
1219 return m_v4Engine->hasException;
1220}
1221
1222/*!
1223 * If an exception is currently pending, catches it and returns it as a
1224 * QJSValue. Otherwise returns undefined as QJSValue. After calling this method
1225 * hasError() returns \c false.
1226 *
1227 * \since Qt 6.1
1228 */
1229QJSValue QJSEngine::catchError()
1230{
1231 if (m_v4Engine->hasException)
1232 return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
1233 else
1234 return QJSValue();
1235}
1236
1237/*!
1238 \property QJSEngine::uiLanguage
1239 \brief the language to be used for translating user interface strings
1240 \since 5.15
1241
1242 This property holds the name of the language to be used for user interface
1243 string translations. It is exposed for reading and writing as \c{Qt.uiLanguage} when
1244 the QJSEngine::TranslationExtension is installed on the engine. It is always exposed
1245 in instances of QQmlEngine.
1246
1247 You can set the value freely and use it in bindings. It is recommended to set it
1248 after installing translators in your application. By convention, an empty string
1249 means no translation from the language used in the source code is intended to occur.
1250*/
1251void QJSEngine::setUiLanguage(const QString &language) {
1252 Q_D(QJSEngine);
1253 d->uiLanguage = language; // property takes care of signal emission if necessary
1254}
1255
1256QString QJSEngine::uiLanguage() const
1257{
1258 Q_D(const QJSEngine);
1259 return d->uiLanguage;
1260}
1261
1262QJSEnginePrivate *QJSEnginePrivate::get(QV4::ExecutionEngine *e)
1263{
1264 return e->jsEngine()->d_func();
1265}
1266
1267QJSEnginePrivate::~QJSEnginePrivate() = default;
1268
1269void QJSEnginePrivate::addToDebugServer(QJSEngine *q)
1270{
1271 if (QCoreApplication::instance()->thread() != q->thread())
1272 return;
1273
1274 QQmlDebugConnector *server = QQmlDebugConnector::instance();
1275 if (!server || server->hasEngine(q))
1276 return;
1277
1278 server->open();
1279 server->addEngine(q);
1280}
1281
1282void QJSEnginePrivate::removeFromDebugServer(QJSEngine *q)
1283{
1284 QQmlDebugConnector *server = QQmlDebugConnector::instance();
1285 if (server && server->hasEngine(q))
1286 server->removeEngine(q);
1287}
1288
1289/*!
1290 \since 5.5
1291 \relates QJSEngine
1292
1293 Returns the QJSEngine associated with \a object, if any.
1294
1295 This function is useful if you have exposed a QObject to the JavaScript environment
1296 and later in your program would like to regain access. It does not require you to
1297 keep the wrapper around that was returned from QJSEngine::newQObject().
1298 */
1299QJSEngine *qjsEngine(const QObject *object)
1300{
1301 QQmlData *data = QQmlData::get(object);
1302 if (!data || data->jsWrapper.isNullOrUndefined())
1303 return nullptr;
1304 return data->jsWrapper.engine()->jsEngine();
1305}
1306
1307
1308/*!
1309 \enum QJSEngine::ObjectOwnership
1310
1311 ObjectOwnership controls whether or not the JavaScript memory manager automatically destroys the
1312 QObject when the corresponding JavaScript object is garbage collected by the
1313 engine. The two ownership options are:
1314
1315 \value CppOwnership The object is owned by C++ code and the JavaScript memory manager will never
1316 delete it. The JavaScript destroy() method cannot be used on these objects. This
1317 option is similar to QScriptEngine::QtOwnership.
1318
1319 \value JavaScriptOwnership The object is owned by JavaScript. When the object
1320 is returned to the JavaScript memory manager as the return value of a method call, the JavaScript
1321 memory manager will track it and delete it if there are no remaining JavaScript references to it
1322 and it has no QObject::parent(). An object tracked by one QJSEngine will be deleted during that
1323 QJSEngine's destructor. Thus, JavaScript references between objects with JavaScriptOwnership from
1324 two different engines will not be valid if one of these engines is deleted. This option is similar
1325 to QScriptEngine::ScriptOwnership.
1326
1327 Generally an application doesn't need to set an object's ownership explicitly. The JavaScript
1328 memory manager uses a heuristic to set the default ownership. By default, an object that is
1329 created by the JavaScript memory manager has JavaScriptOwnership. The exception to this are the
1330 root objects created by calling QQmlComponent::create() or QQmlComponent::beginCreate(), which
1331 have CppOwnership by default. The ownership of these root-level objects is considered to have been
1332 transferred to the C++ caller.
1333
1334 Objects not-created by the JavaScript memory manager have CppOwnership by default. The exception
1335 to this are objects returned from C++ method calls; their ownership will be set to
1336 JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE methods or slots,
1337 but not to property getter invocations.
1338
1339 Calling setObjectOwnership() overrides the default ownership.
1340
1341 \sa {Data Ownership}
1342*/
1343
1344/*!
1345 Sets the \a ownership of \a object.
1346
1347 An object with \c JavaScriptOwnership is not garbage collected as long
1348 as it still has a parent, even if there are no references to it.
1349
1350 \sa QJSEngine::ObjectOwnership
1351*/
1352void QJSEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
1353{
1354 if (!object)
1355 return;
1356
1357 QQmlData *ddata = QQmlData::get(object, true);
1358 if (!ddata)
1359 return;
1360
1361 ddata->indestructible = (ownership == CppOwnership)?true:false;
1362 ddata->explicitIndestructibleSet = true;
1363}
1364
1365/*!
1366 Returns the ownership of \a object.
1367
1368 \sa QJSEngine::ObjectOwnership
1369*/
1370QJSEngine::ObjectOwnership QJSEngine::objectOwnership(QObject *object)
1371{
1372 if (!object)
1373 return CppOwnership;
1374
1375 QQmlData *ddata = QQmlData::get(object, false);
1376 if (!ddata)
1377 return CppOwnership;
1378 else
1379 return ddata->indestructible?CppOwnership:JavaScriptOwnership;
1380}
1381
1382QT_END_NAMESPACE
1383
1384#include "moc_qjsengine.cpp"
QJSEngine * qjsEngine(const QObject *object)