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