1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "config.h"
41#include "qscriptqobject_p.h"
42
43#include <QtCore/qmetaobject.h>
44#include <QtCore/qvarlengtharray.h>
45#include <QtCore/qdebug.h>
46#include <QtScript/qscriptable.h>
47#include "../api/qscriptengine_p.h"
48#include "../api/qscriptable_p.h"
49#include "../api/qscriptcontext_p.h"
50#include "qscriptfunction_p.h"
51#include "qscriptactivationobject_p.h"
52
53#include "Error.h"
54#include "PrototypeFunction.h"
55#include "NativeFunctionWrapper.h"
56#include "PropertyNameArray.h"
57#include "JSFunction.h"
58#include "JSString.h"
59#include "JSValue.h"
60#include "JSArray.h"
61#include "RegExpObject.h"
62#include "RegExpConstructor.h"
63
64namespace JSC
65{
66QT_USE_NAMESPACE
67ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectPrototype);
68ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectWrapperObject);
69ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectPrototype);
70ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
71ASSERT_CLASS_FITS_IN_CELL(QScript::QtPropertyFunction);
72}
73
74QT_BEGIN_NAMESPACE
75
76namespace QScript
77{
78
79struct QObjectConnection
80{
81 uint marked:1;
82 uint slotIndex:31;
83 JSC::JSValue receiver;
84 JSC::JSValue slot;
85 JSC::JSValue senderWrapper;
86
87 QObjectConnection(int i, JSC::JSValue r, JSC::JSValue s,
88 JSC::JSValue sw)
89 : marked(false), slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {}
90 QObjectConnection() : marked(false), slotIndex(0) {}
91
92 bool hasTarget(JSC::JSValue r, JSC::JSValue s) const
93 {
94 if ((r && r.isObject()) != (receiver && receiver.isObject()))
95 return false;
96 if (((r && r.isObject()) && (receiver && receiver.isObject()))
97 && (r != receiver)) {
98 return false;
99 }
100 return (s == slot);
101 }
102
103 bool hasWeaklyReferencedSender() const
104 {
105 if (senderWrapper) {
106 Q_ASSERT(senderWrapper.inherits(&QScriptObject::info));
107 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: senderWrapper));
108 if (!JSC::Heap::isCellMarked(cell: scriptObject)) {
109 QScriptObjectDelegate *delegate = scriptObject->delegate();
110 Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
111 QObjectDelegate *inst = static_cast<QObjectDelegate*>(delegate);
112 if ((inst->ownership() == QScriptEngine::ScriptOwnership)
113 || ((inst->ownership() == QScriptEngine::AutoOwnership)
114 && !inst->hasParent())) {
115 return true;
116 }
117 }
118 }
119 return false;
120 }
121
122 void mark(JSC::MarkStack& markStack)
123 {
124 Q_ASSERT(!marked);
125 if (senderWrapper)
126 markStack.append(value: senderWrapper);
127 if (receiver)
128 markStack.append(value: receiver);
129 if (slot)
130 markStack.append(value: slot);
131 marked = true;
132 }
133};
134
135class QObjectConnectionManager: public QObject
136{
137 Q_OBJECT_FAKE
138public:
139 QObjectConnectionManager(QScriptEnginePrivate *engine);
140 ~QObjectConnectionManager();
141
142 bool addSignalHandler(QObject *sender, int signalIndex,
143 JSC::JSValue receiver,
144 JSC::JSValue slot,
145 JSC::JSValue senderWrapper,
146 Qt::ConnectionType type);
147 bool removeSignalHandler(QObject *sender, int signalIndex,
148 JSC::JSValue receiver,
149 JSC::JSValue slot);
150
151 void execute(int slotIndex, void **argv);
152
153 void clearMarkBits();
154 int mark(JSC::MarkStack&);
155
156private:
157 QScriptEnginePrivate *engine;
158 int slotCounter;
159 QVector<QVector<QObjectConnection> > connections;
160};
161
162static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
163{
164 static const int deleteLaterIndex = QObject::staticMetaObject.indexOfMethod(method: "deleteLater()");
165 return (method.access() != QMetaMethod::Private)
166 && ((index != deleteLaterIndex) || !(opt & QScriptEngine::ExcludeDeleteLater))
167 && (!(opt & QScriptEngine::ExcludeSlots) || (method.methodType() != QMetaMethod::Slot));
168}
169
170static bool isEnumerableMetaProperty(const QMetaProperty &prop,
171 const QMetaObject *mo, int index)
172{
173 return prop.isScriptable() && prop.isValid()
174 // the following lookup is to ensure that we have the
175 // "most derived" occurrence of the property with this name
176 && (mo->indexOfProperty(name: prop.name()) == index);
177}
178
179static const bool GeneratePropertyFunctions = true;
180
181static unsigned flagsForMetaProperty(const QMetaProperty &prop)
182{
183 return (JSC::DontDelete
184 | (!prop.isWritable() ? unsigned(JSC::ReadOnly) : unsigned(0))
185 | (GeneratePropertyFunctions
186 ? unsigned(JSC::Getter | JSC::Setter)
187 : unsigned(0))
188 | QObjectMemberAttribute);
189}
190
191static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
192{
193 QByteArray scope;
194 QByteArray name;
195 int scopeIdx = str.lastIndexOf(c: "::");
196 if (scopeIdx != -1) {
197 scope = str.left(len: scopeIdx);
198 name = str.mid(index: scopeIdx + 2);
199 } else {
200 name = str;
201 }
202 for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
203 QMetaEnum m = meta->enumerator(index: i);
204 if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
205 return i;
206 }
207 return -1;
208}
209
210static inline QScriptable *scriptableFromQObject(QObject *qobj)
211{
212 void *ptr = qobj->qt_metacast("QScriptable");
213 return reinterpret_cast<QScriptable*>(ptr);
214}
215
216QtFunction::QtFunction(JSC::JSValue object, int initialIndex, bool maybeOverloaded,
217 JSC::JSGlobalData *data, WTF::PassRefPtr<JSC::Structure> sid,
218 const JSC::Identifier &ident)
219 : JSC::InternalFunction(data, sid, ident),
220 data(new Data(object, initialIndex, maybeOverloaded))
221{
222}
223
224QtFunction::~QtFunction()
225{
226 delete data;
227}
228
229JSC::CallType QtFunction::getCallData(JSC::CallData &callData)
230{
231 callData.native.function = call;
232 return JSC::CallTypeHost;
233}
234
235void QtFunction::markChildren(JSC::MarkStack& markStack)
236{
237 if (data->object)
238 markStack.append(value: data->object);
239 JSC::InternalFunction::markChildren(markStack);
240}
241
242QScriptObject *QtFunction::wrapperObject() const
243{
244 Q_ASSERT(JSC::asObject(data->object)->inherits(&QScriptObject::info));
245 return static_cast<QScriptObject*>(JSC::asObject(value: data->object));
246}
247
248QObject *QtFunction::qobject() const
249{
250 QScriptObject *scriptObject = wrapperObject();
251 QScriptObjectDelegate *delegate = scriptObject->delegate();
252 Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
253 return static_cast<QScript::QObjectDelegate*>(delegate)->value();
254}
255
256const QMetaObject *QtFunction::metaObject() const
257{
258 QObject *qobj = qobject();
259 if (!qobj)
260 return 0;
261 return qobj->metaObject();
262}
263
264int QtFunction::initialIndex() const
265{
266 return data->initialIndex;
267}
268
269bool QtFunction::maybeOverloaded() const
270{
271 return data->maybeOverloaded;
272}
273
274int QtFunction::mostGeneralMethod(QMetaMethod *out) const
275{
276 const QMetaObject *meta = metaObject();
277 if (!meta)
278 return -1;
279 int index = initialIndex();
280 QMetaMethod method = meta->method(index);
281 if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) {
282 // find the most general method
283 do {
284 method = meta->method(index: --index);
285 } while (method.attributes() & QMetaMethod::Cloned);
286 }
287 if (out)
288 *out = method;
289 return index;
290}
291
292QList<int> QScript::QtFunction::overloadedIndexes() const
293{
294 if (!maybeOverloaded())
295 return QList<int>();
296 QList<int> result;
297 const QMetaObject *meta = metaObject();
298 QMetaMethod method = meta->method(index: initialIndex());
299 QByteArray name = method.name();
300 for (int index = mostGeneralMethod() - 1; index >= 0; --index) {
301 if (meta->method(index).name() == name)
302 result.append(t: index);
303 }
304 return result;
305}
306
307class QScriptMetaType
308{
309public:
310 enum Kind {
311 Invalid,
312 Variant,
313 MetaType,
314 Unresolved,
315 MetaEnum
316 };
317
318 inline QScriptMetaType()
319 : m_kind(Invalid) { }
320
321 inline Kind kind() const
322 { return m_kind; }
323
324 int typeId() const;
325
326 inline bool isValid() const
327 { return (m_kind != Invalid); }
328
329 inline bool isVariant() const
330 { return (m_kind == Variant); }
331
332 inline bool isMetaType() const
333 { return (m_kind == MetaType); }
334
335 inline bool isUnresolved() const
336 { return (m_kind == Unresolved); }
337
338 inline bool isMetaEnum() const
339 { return (m_kind == MetaEnum); }
340
341 QByteArray name() const;
342
343 inline int enumeratorIndex() const
344 { Q_ASSERT(isMetaEnum()); return m_typeId; }
345
346 inline bool operator==(const QScriptMetaType &other) const
347 {
348 return (m_kind == other.m_kind) && (m_typeId == other.m_typeId);
349 }
350
351 static inline QScriptMetaType variant()
352 { return QScriptMetaType(Variant); }
353
354 static inline QScriptMetaType metaType(int typeId, const QByteArray &name)
355 { return QScriptMetaType(MetaType, typeId, name); }
356
357 static inline QScriptMetaType metaEnum(int enumIndex, const QByteArray &name)
358 { return QScriptMetaType(MetaEnum, enumIndex, name); }
359
360 static inline QScriptMetaType unresolved(const QByteArray &name)
361 { return QScriptMetaType(Unresolved, /*typeId=*/0, name); }
362
363private:
364 inline QScriptMetaType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
365 : m_kind(kind), m_typeId(typeId), m_name(name) { }
366
367 Kind m_kind;
368 int m_typeId;
369 QByteArray m_name;
370};
371
372int QScriptMetaType::typeId() const
373{
374 if (isVariant())
375 return QMetaType::QVariant;
376 return isMetaEnum() ? QMetaType::Int : m_typeId;
377}
378
379QByteArray QScriptMetaType::name() const
380{
381 if (!m_name.isEmpty())
382 return m_name;
383 else if (m_kind == Variant)
384 return "QVariant";
385 return QMetaType::typeName(type: typeId());
386}
387
388class QScriptMetaMethod
389{
390public:
391 inline QScriptMetaMethod()
392 { }
393 inline QScriptMetaMethod(const QVector<QScriptMetaType> &types)
394 : m_types(types), m_firstUnresolvedIndex(-1)
395 {
396 QVector<QScriptMetaType>::const_iterator it;
397 for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) {
398 if ((*it).kind() == QScriptMetaType::Unresolved) {
399 m_firstUnresolvedIndex = it - m_types.constBegin();
400 break;
401 }
402 }
403 }
404 inline bool isValid() const
405 { return !m_types.isEmpty(); }
406
407 inline QScriptMetaType returnType() const
408 { return m_types.at(i: 0); }
409
410 inline int argumentCount() const
411 { return m_types.count() - 1; }
412
413 inline QScriptMetaType argumentType(int arg) const
414 { return m_types.at(i: arg + 1); }
415
416 inline bool fullyResolved() const
417 { return m_firstUnresolvedIndex == -1; }
418
419 inline bool hasUnresolvedReturnType() const
420 { return (m_firstUnresolvedIndex == 0); }
421
422 inline int firstUnresolvedIndex() const
423 { return m_firstUnresolvedIndex; }
424
425 inline int count() const
426 { return m_types.count(); }
427
428 inline QScriptMetaType type(int index) const
429 { return m_types.at(i: index); }
430
431 inline QVector<QScriptMetaType> types() const
432 { return m_types; }
433
434private:
435 QVector<QScriptMetaType> m_types;
436 int m_firstUnresolvedIndex;
437};
438
439struct QScriptMetaArguments
440{
441 int matchDistance;
442 int index;
443 QScriptMetaMethod method;
444 QVarLengthArray<QVariant, 9> args;
445
446 inline QScriptMetaArguments(int dist, int idx, const QScriptMetaMethod &mtd,
447 const QVarLengthArray<QVariant, 9> &as)
448 : matchDistance(dist), index(idx), method(mtd), args(as) { }
449 inline QScriptMetaArguments()
450 : index(-1) { }
451
452 inline bool isValid() const
453 { return (index != -1); }
454};
455
456static QMetaMethod metaMethod(const QMetaObject *meta,
457 QMetaMethod::MethodType type,
458 int index)
459{
460 if (type != QMetaMethod::Constructor)
461 return meta->method(index);
462 else
463 return meta->constructor(index);
464}
465
466/*!
467 \internal
468 Derives the actual method to call based on the script arguments,
469 \a scriptArgs, and delegates it to the given \a delegate.
470*/
471template <class Delegate>
472static JSC::JSValue delegateQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType,
473 const JSC::ArgList &scriptArgs, const QMetaObject *meta,
474 int initialIndex, bool maybeOverloaded, Delegate &delegate)
475{
476 QScriptMetaMethod chosenMethod;
477 int chosenIndex = -1;
478 QVarLengthArray<QVariant, 9> args;
479 QVector<QScriptMetaArguments> candidates;
480 QVector<QScriptMetaArguments> unresolved;
481 QVector<int> tooFewArgs;
482 QVector<int> conversionFailed;
483 int index;
484 QByteArray methodName;
485 exec->clearException();
486 for (index = initialIndex; index >= 0; --index) {
487 QMetaMethod method = metaMethod(meta, type: callType, index);
488
489 if (index == initialIndex)
490 methodName = method.name();
491 else if (method.name() != methodName)
492 continue;
493
494 QList<QByteArray> parameterTypeNames = method.parameterTypes();
495
496 QVector<QScriptMetaType> types;
497 types.resize(size: 1 + parameterTypeNames.size());
498 QScriptMetaType *typesData = types.data();
499 // resolve return type
500 QByteArray returnTypeName = method.typeName();
501 int rtype = method.returnType();
502 if ((rtype == QMetaType::UnknownType) && !returnTypeName.isEmpty()) {
503 int enumIndex = indexOfMetaEnum(meta, str: returnTypeName);
504 if (enumIndex != -1)
505 typesData[0] = QScriptMetaType::metaEnum(enumIndex, name: returnTypeName);
506 else
507 typesData[0] = QScriptMetaType::unresolved(name: returnTypeName);
508 } else {
509 if (callType == QMetaMethod::Constructor)
510 typesData[0] = QScriptMetaType::metaType(typeId: QMetaType::QObjectStar, name: "QObject*");
511 else if (rtype == QMetaType::QVariant)
512 typesData[0] = QScriptMetaType::variant();
513 else
514 typesData[0] = QScriptMetaType::metaType(typeId: rtype, name: returnTypeName);
515 }
516
517 // resolve argument types
518 for (int i = 0; i < parameterTypeNames.count(); ++i) {
519 QByteArray argTypeName = parameterTypeNames.at(i);
520 int atype = QMetaType::type(typeName: argTypeName);
521 if (atype == QMetaType::UnknownType) {
522 int enumIndex = indexOfMetaEnum(meta, str: argTypeName);
523 if (enumIndex != -1)
524 typesData[1 + i] = QScriptMetaType::metaEnum(enumIndex, name: argTypeName);
525 else
526 typesData[1 + i] = QScriptMetaType::unresolved(name: argTypeName);
527 } else if (atype == QMetaType::QVariant) {
528 typesData[1 + i] = QScriptMetaType::variant();
529 } else {
530 typesData[1 + i] = QScriptMetaType::metaType(typeId: atype, name: argTypeName);
531 }
532 }
533
534 QScriptMetaMethod mtd = QScriptMetaMethod(types);
535
536 if (int(scriptArgs.size()) < mtd.argumentCount()) {
537 tooFewArgs.append(t: index);
538 continue;
539 }
540
541 if (!mtd.fullyResolved()) {
542 // remember it so we can give an error message later, if necessary
543 unresolved.append(t: QScriptMetaArguments(/*matchDistance=*/INT_MAX, index,
544 mtd, QVarLengthArray<QVariant, 9>()));
545 if (mtd.hasUnresolvedReturnType())
546 continue;
547 }
548
549 if (args.count() != mtd.count())
550 args.resize(size: mtd.count());
551
552 if (rtype != QMetaType::Void) {
553 // initialize the result
554 args[0] = QVariant(rtype, (void *)0);
555 }
556
557 // try to convert arguments
558 bool converted = true;
559 int matchDistance = 0;
560 for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
561 JSC::JSValue actual;
562 if (i < (int)scriptArgs.size())
563 actual = scriptArgs.at(idx: i);
564 else
565 actual = JSC::jsUndefined();
566 QScriptMetaType argType = mtd.argumentType(arg: i);
567 int tid = -1;
568 QVariant v;
569 if (argType.isUnresolved()) {
570 v = QVariant(QMetaType::QObjectStar, (void *)0);
571 converted = QScriptEnginePrivate::convertToNativeQObject(
572 exec, actual, targetType: argType.name(), result: reinterpret_cast<void* *>(v.data()));
573 } else if (argType.isVariant()) {
574 if (QScriptEnginePrivate::isVariant(value: actual)) {
575 v = QScriptEnginePrivate::variantValue(value: actual);
576 } else {
577 v = QScriptEnginePrivate::toVariant(exec, actual);
578 converted = v.isValid() || actual.isUndefined() || actual.isNull();
579 }
580 } else {
581 tid = argType.typeId();
582 v = QVariant(tid, (void *)0);
583 converted = QScriptEnginePrivate::convertValue(exec, value: actual, type: tid, ptr: v.data());
584 if (exec->hadException())
585 return exec->exception();
586 }
587
588 if (!converted) {
589 if (QScriptEnginePrivate::isVariant(value: actual)) {
590 if (tid == -1)
591 tid = argType.typeId();
592 QVariant vv = QScriptEnginePrivate::variantValue(value: actual);
593 if (vv.canConvert(targetTypeId: tid)) {
594 v = vv;
595 converted = v.convert(targetTypeId: tid);
596 if (converted && (vv.userType() != tid))
597 matchDistance += 10;
598 } else {
599 QByteArray vvTypeName = vv.typeName();
600 if (vvTypeName.endsWith(c: '*')
601 && (vvTypeName.left(len: vvTypeName.size()-1) == argType.name())) {
602 v = QVariant(tid, *reinterpret_cast<void* *>(vv.data()));
603 converted = true;
604 matchDistance += 10;
605 }
606 }
607 } else if (actual.isNumber() || actual.isString()) {
608 // see if it's an enum value
609 QMetaEnum m;
610 if (argType.isMetaEnum()) {
611 m = meta->enumerator(index: argType.enumeratorIndex());
612 } else {
613 int mi = indexOfMetaEnum(meta, str: argType.name());
614 if (mi != -1)
615 m = meta->enumerator(index: mi);
616 }
617 if (m.isValid()) {
618 if (actual.isNumber()) {
619 int ival = QScriptEnginePrivate::toInt32(exec, value: actual);
620 if (m.valueToKey(value: ival) != 0) {
621 v.setValue(ival);
622 converted = true;
623 matchDistance += 10;
624 }
625 } else {
626 JSC::UString sval = QScriptEnginePrivate::toString(exec, value: actual);
627 int ival = m.keyToValue(key: convertToLatin1(str: sval));
628 if (ival != -1) {
629 v.setValue(ival);
630 converted = true;
631 matchDistance += 10;
632 }
633 }
634 }
635 }
636 } else {
637 // determine how well the conversion matched
638 if (actual.isNumber()) {
639 switch (tid) {
640 case QMetaType::Double:
641 // perfect
642 break;
643 case QMetaType::Float:
644 matchDistance += 1;
645 break;
646 case QMetaType::LongLong:
647 case QMetaType::ULongLong:
648 matchDistance += 2;
649 break;
650 case QMetaType::Long:
651 case QMetaType::ULong:
652 matchDistance += 3;
653 break;
654 case QMetaType::Int:
655 case QMetaType::UInt:
656 matchDistance += 4;
657 break;
658 case QMetaType::Short:
659 case QMetaType::UShort:
660 matchDistance += 5;
661 break;
662 case QMetaType::Char:
663 case QMetaType::UChar:
664 matchDistance += 6;
665 break;
666 default:
667 matchDistance += 10;
668 break;
669 }
670 } else if (actual.isString()) {
671 switch (tid) {
672 case QMetaType::QString:
673 // perfect
674 break;
675 default:
676 matchDistance += 10;
677 break;
678 }
679 } else if (actual.isBoolean()) {
680 switch (tid) {
681 case QMetaType::Bool:
682 // perfect
683 break;
684 default:
685 matchDistance += 10;
686 break;
687 }
688 } else if (QScriptEnginePrivate::isDate(value: actual)) {
689 switch (tid) {
690 case QMetaType::QDateTime:
691 // perfect
692 break;
693 case QMetaType::QDate:
694 matchDistance += 1;
695 break;
696 case QMetaType::QTime:
697 matchDistance += 2;
698 break;
699 default:
700 matchDistance += 10;
701 break;
702 }
703 } else if (QScriptEnginePrivate::isRegExp(value: actual)) {
704 switch (tid) {
705 case QMetaType::QRegExp:
706 // perfect
707 break;
708 default:
709 matchDistance += 10;
710 break;
711 }
712 } else if (QScriptEnginePrivate::isVariant(value: actual)) {
713 if (argType.isVariant()
714 || (QScriptEnginePrivate::toVariant(exec, actual).userType() == tid)) {
715 // perfect
716 } else {
717 matchDistance += 10;
718 }
719 } else if (QScriptEnginePrivate::isArray(value: actual)) {
720 switch (tid) {
721 case QMetaType::QStringList:
722 case QMetaType::QVariantList:
723 matchDistance += 5;
724 break;
725 default:
726 matchDistance += 10;
727 break;
728 }
729 } else if (QScriptEnginePrivate::isQObject(value: actual)) {
730 switch (tid) {
731 case QMetaType::QObjectStar:
732 // perfect
733 break;
734 default:
735 if (!(QMetaType::typeFlags(type: tid) & QMetaType::PointerToQObject))
736 matchDistance += 10;
737 break;
738 }
739 } else if (actual.isNull()) {
740 switch (tid) {
741 case QMetaType::VoidStar:
742 case QMetaType::QObjectStar:
743 // perfect
744 break;
745 default:
746 if (!argType.name().endsWith(c: '*'))
747 matchDistance += 10;
748 break;
749 }
750 } else {
751 matchDistance += 10;
752 }
753 }
754
755 if (converted)
756 args[i+1] = v;
757 }
758
759 if (converted) {
760 if ((scriptArgs.size() == (size_t)mtd.argumentCount())
761 && (matchDistance == 0)) {
762 // perfect match, use this one
763 chosenMethod = mtd;
764 chosenIndex = index;
765 break;
766 } else {
767 bool redundant = false;
768 if ((callType != QMetaMethod::Constructor)
769 && (index < meta->methodOffset())) {
770 // it is possible that a virtual method is redeclared in a subclass,
771 // in which case we want to ignore the superclass declaration
772 for (int i = 0; i < candidates.size(); ++i) {
773 const QScriptMetaArguments &other = candidates.at(i);
774 if (mtd.types() == other.method.types()) {
775 redundant = true;
776 break;
777 }
778 }
779 }
780 if (!redundant) {
781 QScriptMetaArguments metaArgs(matchDistance, index, mtd, args);
782 if (candidates.isEmpty()) {
783 candidates.append(t: metaArgs);
784 } else {
785 const QScriptMetaArguments &otherArgs = candidates.at(i: 0);
786 if ((args.count() > otherArgs.args.count())
787 || ((args.count() == otherArgs.args.count())
788 && (matchDistance <= otherArgs.matchDistance))) {
789 candidates.prepend(t: metaArgs);
790 } else {
791 candidates.append(t: metaArgs);
792 }
793 }
794 }
795 }
796 } else if (mtd.fullyResolved()) {
797 conversionFailed.append(t: index);
798 }
799
800 if (!maybeOverloaded)
801 break;
802 }
803
804 JSC::JSValue result;
805 if ((chosenIndex == -1) && candidates.isEmpty()) {
806// context->calleeMetaIndex = initialIndex;
807//#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
808// engine->notifyFunctionEntry(context);
809//#endif
810 QString funName = QString::fromLatin1(str: methodName);
811 if (!conversionFailed.isEmpty()) {
812 QString message = QString::fromLatin1(str: "incompatible type of argument(s) in call to %0(); candidates were\n")
813 .arg(a: funName);
814 for (int i = 0; i < conversionFailed.size(); ++i) {
815 if (i > 0)
816 message += QLatin1String("\n");
817 QMetaMethod mtd = metaMethod(meta, type: callType, index: conversionFailed.at(i));
818 message += QString::fromLatin1(str: " %0").arg(a: QString::fromLatin1(str: mtd.methodSignature().constData()));
819 }
820 result = JSC::throwError(exec, JSC::TypeError, message);
821 } else if (!unresolved.isEmpty()) {
822 QScriptMetaArguments argsInstance = unresolved.first();
823 int unresolvedIndex = argsInstance.method.firstUnresolvedIndex();
824 Q_ASSERT(unresolvedIndex != -1);
825 QScriptMetaType unresolvedType = argsInstance.method.type(index: unresolvedIndex);
826 QString unresolvedTypeName = QString::fromLatin1(str: unresolvedType.name());
827 QString message = QString::fromLatin1(str: "cannot call %0(): ")
828 .arg(a: funName);
829 if (unresolvedIndex > 0) {
830 message.append(s: QString::fromLatin1(str: "argument %0 has unknown type `%1'").
831 arg(a: unresolvedIndex).arg(a: unresolvedTypeName));
832 } else {
833 message.append(s: QString::fromLatin1(str: "unknown return type `%0'")
834 .arg(a: unresolvedTypeName));
835 }
836 message.append(s: QString::fromLatin1(str: " (register the type with qScriptRegisterMetaType())"));
837 result = JSC::throwError(exec, JSC::TypeError, message);
838 } else {
839 QString message = QString::fromLatin1(str: "too few arguments in call to %0(); candidates are\n")
840 .arg(a: funName);
841 for (int i = 0; i < tooFewArgs.size(); ++i) {
842 if (i > 0)
843 message += QLatin1String("\n");
844 QMetaMethod mtd = metaMethod(meta, type: callType, index: tooFewArgs.at(i));
845 message += QString::fromLatin1(str: " %0").arg(a: QString::fromLatin1(str: mtd.methodSignature().constData()));
846 }
847 result = JSC::throwError(exec, JSC::SyntaxError, message);
848 }
849 } else {
850 if (chosenIndex == -1) {
851 QScriptMetaArguments metaArgs = candidates.at(i: 0);
852 if ((candidates.size() > 1)
853 && (metaArgs.args.count() == candidates.at(i: 1).args.count())
854 && (metaArgs.matchDistance == candidates.at(i: 1).matchDistance)) {
855 // ambiguous call
856 QString message = QString::fromLatin1(str: "ambiguous call of overloaded function %0(); candidates were\n")
857 .arg(a: QLatin1String(methodName));
858 for (int i = 0; i < candidates.size(); ++i) {
859 if (i > 0)
860 message += QLatin1String("\n");
861 QMetaMethod mtd = metaMethod(meta, type: callType, index: candidates.at(i).index);
862 message += QString::fromLatin1(str: " %0").arg(a: QString::fromLatin1(str: mtd.methodSignature().constData()));
863 }
864 result = JSC::throwError(exec, JSC::TypeError, message);
865 } else {
866 chosenMethod = metaArgs.method;
867 chosenIndex = metaArgs.index;
868 args = metaArgs.args;
869 }
870 }
871
872 if (chosenIndex != -1)
873 result = delegate(exec, callType, meta, chosenMethod, chosenIndex, args);
874 }
875
876 return result;
877}
878
879struct QtMethodCaller
880{
881 QtMethodCaller(QObject *o)
882 : thisQObject(o)
883 {}
884 JSC::JSValue operator()(JSC::ExecState *exec, QMetaMethod::MethodType callType,
885 const QMetaObject *meta, const QScriptMetaMethod &chosenMethod,
886 int chosenIndex, const QVarLengthArray<QVariant, 9> &args)
887 {
888 JSC::JSValue result;
889
890 QVarLengthArray<void*, 9> array(args.count());
891 void **params = array.data();
892 for (int i = 0; i < args.count(); ++i) {
893 const QVariant &v = args[i];
894 switch (chosenMethod.type(index: i).kind()) {
895 case QScriptMetaType::Variant:
896 params[i] = const_cast<QVariant*>(&v);
897 break;
898 case QScriptMetaType::MetaType:
899 case QScriptMetaType::MetaEnum:
900 case QScriptMetaType::Unresolved:
901 params[i] = const_cast<void*>(v.constData());
902 break;
903 default:
904 Q_ASSERT(0);
905 }
906 }
907
908 QScriptable *scriptable = 0;
909 if (thisQObject)
910 scriptable = scriptableFromQObject(qobj: thisQObject);
911 QScriptEngine *oldEngine = 0;
912 QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec);
913 if (scriptable) {
914 oldEngine = QScriptablePrivate::get(q: scriptable)->engine;
915 QScriptablePrivate::get(q: scriptable)->engine = QScriptEnginePrivate::get(d: engine);
916 }
917
918 // ### fixme
919 //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
920 // engine->notifyFunctionEntry(context);
921 //#endif
922
923 if (callType == QMetaMethod::Constructor) {
924 Q_ASSERT(meta != 0);
925 meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
926 } else {
927 QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params);
928 }
929
930 if (scriptable)
931 QScriptablePrivate::get(q: scriptable)->engine = oldEngine;
932
933 if (exec->hadException()) {
934 result = exec->exception() ; // propagate
935 } else {
936 QScriptMetaType retType = chosenMethod.returnType();
937 if (retType.isVariant()) {
938 result = QScriptEnginePrivate::jscValueFromVariant(exec, v: *(QVariant *)params[0]);
939 } else if (retType.typeId() != QMetaType::Void) {
940 result = QScriptEnginePrivate::create(exec, type: retType.typeId(), ptr: params[0]);
941 if (!result)
942 result = engine->newVariant(QVariant(retType.typeId(), params[0]));
943 } else {
944 result = JSC::jsUndefined();
945 }
946 }
947
948 return result;
949 }
950
951private:
952 QObject *thisQObject;
953};
954
955static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType,
956 QObject *thisQObject, const JSC::ArgList &scriptArgs,
957 const QMetaObject *meta, int initialIndex,
958 bool maybeOverloaded)
959{
960 QtMethodCaller caller(thisQObject);
961 return delegateQtMethod<QtMethodCaller>(exec, callType, scriptArgs, meta,
962 initialIndex, maybeOverloaded, delegate&: caller);
963}
964
965JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
966 const JSC::ArgList &scriptArgs)
967{
968 Q_ASSERT(data->object.inherits(&QScriptObject::info));
969 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: data->object));
970 QScriptObjectDelegate *delegate = scriptObject->delegate();
971 Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
972 QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
973 if (!qobj)
974 return JSC::throwError(exec, JSC::GeneralError, message: QString::fromLatin1(str: "cannot call function of deleted QObject"));
975 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
976
977 const QMetaObject *meta = qobj->metaObject();
978 QObject *thisQObject = 0;
979 thisValue = engine->toUsableValue(value: thisValue);
980 if (thisValue.inherits(classInfo: &QScriptObject::info)) {
981 delegate = static_cast<QScriptObject*>(JSC::asObject(value: thisValue))->delegate();
982 if (delegate && (delegate->type() == QScriptObjectDelegate::QtObject))
983 thisQObject = static_cast<QScript::QObjectDelegate*>(delegate)->value();
984 }
985 if (!thisQObject)
986 thisQObject = qobj; // ### TypeError
987
988 if (!meta->cast(obj: thisQObject)) {
989 // invoking a function in the prototype
990 thisQObject = qobj;
991 }
992
993 return callQtMethod(exec, callType: QMetaMethod::Method, thisQObject, scriptArgs,
994 meta, initialIndex: data->initialIndex, maybeOverloaded: data->maybeOverloaded);
995}
996
997const JSC::ClassInfo QtFunction::info = { .className: "QtFunction", .parentClass: &InternalFunction::info, .staticPropHashTable: 0, .classPropHashTableGetterFunction: 0 };
998
999JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject *callee,
1000 JSC::JSValue thisValue, const JSC::ArgList &args)
1001{
1002 if (!callee->inherits(info: &QtFunction::info))
1003 return throwError(exec, JSC::TypeError, message: "callee is not a QtFunction object");
1004 QtFunction *qfun = static_cast<QtFunction*>(callee);
1005 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
1006 JSC::ExecState *previousFrame = eng_p->currentFrame;
1007 eng_p->currentFrame = exec;
1008 eng_p->pushContext(exec, thisObject: thisValue, args, callee);
1009 JSC::JSValue result = qfun->execute(exec: eng_p->currentFrame, thisValue, scriptArgs: args);
1010 eng_p->popContext();
1011 eng_p->currentFrame = previousFrame;
1012 return result;
1013}
1014
1015struct QtMethodIndexReturner
1016{
1017 JSC::JSValue operator()(JSC::ExecState *exec, QMetaMethod::MethodType,
1018 const QMetaObject *, const QScriptMetaMethod &,
1019 int chosenIndex, const QVarLengthArray<QVariant, 9> &)
1020 {
1021 return JSC::jsNumber(exec, i: chosenIndex);
1022 }
1023};
1024
1025/*!
1026 \internal
1027 Returns the specific index of the meta-method that was used in the
1028 function call represented by the given \a context. If the method is
1029 overloaded, the actual parameters that were passed to the function
1030 are used to derive the selected index, matching the behavior of
1031 callQtMethod().
1032*/
1033int QtFunction::specificIndex(const QScriptContext *context) const
1034{
1035 if (!maybeOverloaded())
1036 return initialIndex();
1037 JSC::ExecState *exec = const_cast<JSC::ExecState *>(QScriptEnginePrivate::frameForContext(context));
1038 int argCount = exec->argumentCount();
1039
1040 // Create arguments list wrapper; this logic must match
1041 // JITStubs.cpp op_call_NotJSFunction, and Interpreter.cpp op_call
1042 JSC::Register* argv = exec->registers() - JSC::RegisterFile::CallFrameHeaderSize - argCount;
1043 JSC::ArgList args(argv + 1, argCount - 1);
1044
1045 QtMethodIndexReturner returner;
1046 JSC::JSValue result = delegateQtMethod<QtMethodIndexReturner>(
1047 exec, callType: QMetaMethod::Method, scriptArgs: args, meta: metaObject(),
1048 initialIndex: initialIndex(), maybeOverloaded: maybeOverloaded(), delegate&: returner);
1049 if (exec->hadException() || !result || !result.isInt32())
1050 return initialIndex();
1051 return result.asInt32();
1052}
1053
1054const JSC::ClassInfo QtPropertyFunction::info = { .className: "QtPropertyFunction", .parentClass: &InternalFunction::info, .staticPropHashTable: 0, .classPropHashTableGetterFunction: 0 };
1055
1056QtPropertyFunction::QtPropertyFunction(const QMetaObject *meta, int index,
1057 JSC::JSGlobalData *data,
1058 WTF::PassRefPtr<JSC::Structure> sid,
1059 const JSC::Identifier &ident)
1060 : JSC::InternalFunction(data, sid, ident),
1061 data(new Data(meta, index))
1062{
1063}
1064
1065QtPropertyFunction::~QtPropertyFunction()
1066{
1067 delete data;
1068}
1069
1070JSC::CallType QtPropertyFunction::getCallData(JSC::CallData &callData)
1071{
1072 callData.native.function = call;
1073 return JSC::CallTypeHost;
1074}
1075
1076JSC::JSValue JSC_HOST_CALL QtPropertyFunction::call(
1077 JSC::ExecState *exec, JSC::JSObject *callee,
1078 JSC::JSValue thisValue, const JSC::ArgList &args)
1079{
1080 if (!callee->inherits(info: &QtPropertyFunction::info))
1081 return throwError(exec, JSC::TypeError, message: "callee is not a QtPropertyFunction object");
1082 QtPropertyFunction *qfun = static_cast<QtPropertyFunction*>(callee);
1083 return qfun->execute(exec, thisValue, args);
1084}
1085
1086JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec,
1087 JSC::JSValue thisValue,
1088 const JSC::ArgList &args)
1089{
1090 JSC::JSValue result = JSC::jsUndefined();
1091
1092 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1093 JSC::ExecState *previousFrame = engine->currentFrame;
1094 engine->currentFrame = exec;
1095
1096 JSC::JSValue qobjectValue = engine->toUsableValue(value: thisValue);
1097 QObject *qobject = QScriptEnginePrivate::toQObject(exec, value: qobjectValue);
1098 while ((!qobject || (qobject->metaObject() != data->meta))
1099 && JSC::asObject(value: qobjectValue)->prototype().isObject()) {
1100 qobjectValue = JSC::asObject(value: qobjectValue)->prototype();
1101 qobject = QScriptEnginePrivate::toQObject(exec, value: qobjectValue);
1102 }
1103 Q_ASSERT_X(qobject, Q_FUNC_INFO, "this-object must be a QObject");
1104
1105 QMetaProperty prop = data->meta->property(index: data->index);
1106 Q_ASSERT(prop.isScriptable());
1107 if (args.size() == 0) {
1108 // get
1109 if (prop.isValid()) {
1110 QScriptable *scriptable = scriptableFromQObject(qobj: qobject);
1111 QScriptEngine *oldEngine = 0;
1112 if (scriptable) {
1113 engine->pushContext(exec, thisObject: thisValue, args, callee: this);
1114 oldEngine = QScriptablePrivate::get(q: scriptable)->engine;
1115 QScriptablePrivate::get(q: scriptable)->engine = QScriptEnginePrivate::get(d: engine);
1116 }
1117
1118 QVariant v = prop.read(obj: qobject);
1119
1120 if (scriptable) {
1121 QScriptablePrivate::get(q: scriptable)->engine = oldEngine;
1122 engine->popContext();
1123 }
1124
1125 result = QScriptEnginePrivate::jscValueFromVariant(exec, v);
1126 }
1127 } else {
1128 // set
1129 JSC::JSValue arg = args.at(idx: 0);
1130 QVariant v;
1131 if (prop.isEnumType() && arg.isString()
1132 && !engine->hasDemarshalFunction(type: prop.userType())) {
1133 // give QMetaProperty::write() a chance to convert from
1134 // string to enum value
1135 v = (QString)arg.toString(exec);
1136 } else {
1137 v = QScriptEnginePrivate::jscValueToVariant(exec, value: arg, targetType: prop.userType());
1138 }
1139
1140 QScriptable *scriptable = scriptableFromQObject(qobj: qobject);
1141 QScriptEngine *oldEngine = 0;
1142 if (scriptable) {
1143 engine->pushContext(exec, thisObject: thisValue, args, callee: this);
1144 oldEngine = QScriptablePrivate::get(q: scriptable)->engine;
1145 QScriptablePrivate::get(q: scriptable)->engine = QScriptEnginePrivate::get(d: engine);
1146 }
1147
1148 prop.write(obj: qobject, value: v);
1149
1150 if (scriptable) {
1151 QScriptablePrivate::get(q: scriptable)->engine = oldEngine;
1152 engine->popContext();
1153 }
1154
1155 result = arg;
1156 }
1157 engine->currentFrame = previousFrame;
1158 return result;
1159}
1160
1161const QMetaObject *QtPropertyFunction::metaObject() const
1162{
1163 return data->meta;
1164}
1165
1166int QtPropertyFunction::propertyIndex() const
1167{
1168 return data->index;
1169}
1170
1171
1172QObjectDelegate::QObjectDelegate(
1173 QObject *object, QScriptEngine::ValueOwnership ownership,
1174 const QScriptEngine::QObjectWrapOptions &options)
1175 : data(new Data(object, ownership, options))
1176{
1177}
1178
1179QObjectDelegate::~QObjectDelegate()
1180{
1181 switch (data->ownership) {
1182 case QScriptEngine::QtOwnership:
1183 break;
1184 case QScriptEngine::ScriptOwnership:
1185 if (data->value)
1186 delete data->value; // ### fixme
1187// eng->disposeQObject(value);
1188 break;
1189 case QScriptEngine::AutoOwnership:
1190 if (data->value && !data->value->parent())
1191 delete data->value; // ### fixme
1192// eng->disposeQObject(value);
1193 break;
1194 }
1195 delete data;
1196}
1197
1198QScriptObjectDelegate::Type QObjectDelegate::type() const
1199{
1200 return QtObject;
1201}
1202
1203bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState *exec,
1204 const JSC::Identifier &propertyName,
1205 JSC::PropertySlot &slot)
1206{
1207 //Note: this has to be kept in sync with getOwnPropertyDescriptor
1208#ifndef QT_NO_PROPERTIES
1209 QByteArray name = convertToLatin1(str: propertyName.ustring());
1210 QObject *qobject = data->value;
1211 if (!qobject) {
1212 QString message = QString::fromLatin1(str: "cannot access member `%0' of deleted QObject")
1213 .arg(a: QString::fromLatin1(str: name));
1214 slot.setValue(JSC::throwError(exec, JSC::GeneralError, message));
1215 return true;
1216 }
1217
1218 const QMetaObject *meta = qobject->metaObject();
1219 {
1220 QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(key: name);
1221 if (it != data->cachedMembers.constEnd()) {
1222 if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
1223 slot.setGetterSlot(JSC::asObject(value: it.value()));
1224 else
1225 slot.setValue(it.value());
1226 return true;
1227 }
1228 }
1229
1230 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1231 QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
1232 int index = -1;
1233 if (name.contains(c: '(')) {
1234 QByteArray normalized = QMetaObject::normalizedSignature(method: name);
1235 if (-1 != (index = meta->indexOfMethod(method: normalized))) {
1236 QMetaMethod method = meta->method(index);
1237 if (hasMethodAccess(method, index, opt)) {
1238 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1239 || (index >= meta->methodOffset())) {
1240 QtFunction *fun = new (exec)QtFunction(
1241 object, index, /*maybeOverloaded=*/false,
1242 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1243 propertyName);
1244 slot.setValue(fun);
1245 data->cachedMembers.insert(key: name, value: fun);
1246 return true;
1247 }
1248 }
1249 }
1250 }
1251
1252 index = meta->indexOfProperty(name);
1253 if (index != -1) {
1254 QMetaProperty prop = meta->property(index);
1255 if (prop.isScriptable()) {
1256 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1257 || (index >= meta->propertyOffset())) {
1258 if (GeneratePropertyFunctions) {
1259 QtPropertyFunction *fun = new (exec)QtPropertyFunction(
1260 meta, index, &exec->globalData(),
1261 eng->originalGlobalObject()->functionStructure(),
1262 propertyName);
1263 data->cachedMembers.insert(key: name, value: fun);
1264 slot.setGetterSlot(fun);
1265 } else {
1266 JSC::JSValue val;
1267 if (!prop.isValid())
1268 val = JSC::jsUndefined();
1269 else
1270 val = QScriptEnginePrivate::jscValueFromVariant(exec, v: prop.read(obj: qobject));
1271 slot.setValue(val);
1272 }
1273 return true;
1274 }
1275 }
1276 }
1277
1278 index = qobject->dynamicPropertyNames().indexOf(t: name);
1279 if (index != -1) {
1280 JSC::JSValue val = QScriptEnginePrivate::jscValueFromVariant(exec, v: qobject->property(name));
1281 slot.setValue(val);
1282 return true;
1283 }
1284
1285 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1286 ? meta->methodOffset() : 0;
1287 for (index = meta->methodCount() - 1; index >= offset; --index) {
1288 QMetaMethod method = meta->method(index);
1289 if (hasMethodAccess(method, index, opt) && (method.name() == name)) {
1290 QtFunction *fun = new (exec)QtFunction(
1291 object, index, /*maybeOverloaded=*/true,
1292 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1293 propertyName);
1294 slot.setValue(fun);
1295 data->cachedMembers.insert(key: name, value: fun);
1296 return true;
1297 }
1298 }
1299
1300 if (!(opt & QScriptEngine::ExcludeChildObjects)) {
1301 QList<QObject*> children = qobject->children();
1302 for (index = 0; index < children.count(); ++index) {
1303 QObject *child = children.at(i: index);
1304 if (child->objectName() == QString(propertyName.ustring())) {
1305 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1306 slot.setValue(eng->newQObject(object: child, ownership: QScriptEngine::QtOwnership, options: opt));
1307 return true;
1308 }
1309 }
1310 }
1311
1312 return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot);
1313#else //QT_NO_PROPERTIES
1314 return false;
1315#endif //QT_NO_PROPERTIES
1316}
1317
1318
1319bool QObjectDelegate::getOwnPropertyDescriptor(QScriptObject *object, JSC::ExecState *exec,
1320 const JSC::Identifier &propertyName,
1321 JSC::PropertyDescriptor &descriptor)
1322{
1323 //Note: this has to be kept in sync with getOwnPropertySlot
1324#ifndef QT_NO_PROPERTIES
1325 QByteArray name = convertToLatin1(str: propertyName.ustring());
1326 QObject *qobject = data->value;
1327 if (!qobject) {
1328 QString message = QString::fromLatin1(str: "cannot access member `%0' of deleted QObject")
1329 .arg(a: QString::fromLatin1(str: name));
1330 descriptor.setValue(JSC::throwError(exec, JSC::GeneralError, message));
1331 return true;
1332 }
1333
1334 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1335
1336 const QMetaObject *meta = qobject->metaObject();
1337 {
1338 QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(key: name);
1339 if (it != data->cachedMembers.constEnd()) {
1340 int index;
1341 if (GeneratePropertyFunctions && ((index = meta->indexOfProperty(name)) != -1)) {
1342 QMetaProperty prop = meta->property(index);
1343 descriptor.setAccessorDescriptor(getter: it.value(), setter: it.value(), attributes: flagsForMetaProperty(prop));
1344 if (!prop.isWritable())
1345 descriptor.setWritable(false);
1346 } else {
1347 unsigned attributes = QObjectMemberAttribute;
1348 if (opt & QScriptEngine::SkipMethodsInEnumeration)
1349 attributes |= JSC::DontEnum;
1350 descriptor.setDescriptor(value: it.value(), attributes);
1351 }
1352 return true;
1353 }
1354 }
1355
1356 QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
1357 int index = -1;
1358 if (name.contains(c: '(')) {
1359 QByteArray normalized = QMetaObject::normalizedSignature(method: name);
1360 if (-1 != (index = meta->indexOfMethod(method: normalized))) {
1361 QMetaMethod method = meta->method(index);
1362 if (hasMethodAccess(method, index, opt)) {
1363 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1364 || (index >= meta->methodOffset())) {
1365 QtFunction *fun = new (exec)QtFunction(
1366 object, index, /*maybeOverloaded=*/false,
1367 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1368 propertyName);
1369 data->cachedMembers.insert(key: name, value: fun);
1370 unsigned attributes = QObjectMemberAttribute;
1371 if (opt & QScriptEngine::SkipMethodsInEnumeration)
1372 attributes |= JSC::DontEnum;
1373 descriptor.setDescriptor(value: fun, attributes);
1374 return true;
1375 }
1376 }
1377 }
1378 }
1379
1380 index = meta->indexOfProperty(name);
1381 if (index != -1) {
1382 QMetaProperty prop = meta->property(index);
1383 if (prop.isScriptable()) {
1384 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1385 || (index >= meta->propertyOffset())) {
1386 unsigned attributes = flagsForMetaProperty(prop);
1387 if (GeneratePropertyFunctions) {
1388 QtPropertyFunction *fun = new (exec)QtPropertyFunction(
1389 meta, index, &exec->globalData(),
1390 eng->originalGlobalObject()->functionStructure(),
1391 propertyName);
1392 data->cachedMembers.insert(key: name, value: fun);
1393 descriptor.setAccessorDescriptor(getter: fun, setter: fun, attributes);
1394 if (attributes & JSC::ReadOnly)
1395 descriptor.setWritable(false);
1396 } else {
1397 JSC::JSValue val;
1398 if (!prop.isValid())
1399 val = JSC::jsUndefined();
1400 else
1401 val = QScriptEnginePrivate::jscValueFromVariant(exec, v: prop.read(obj: qobject));
1402 descriptor.setDescriptor(value: val, attributes);
1403 }
1404 return true;
1405 }
1406 }
1407 }
1408
1409 index = qobject->dynamicPropertyNames().indexOf(t: name);
1410 if (index != -1) {
1411 JSC::JSValue val = QScriptEnginePrivate::jscValueFromVariant(exec, v: qobject->property(name));
1412 descriptor.setDescriptor(value: val, attributes: QObjectMemberAttribute);
1413 return true;
1414 }
1415
1416 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1417 ? meta->methodOffset() : 0;
1418 for (index = meta->methodCount() - 1; index >= offset; --index) {
1419 QMetaMethod method = meta->method(index);
1420 if (hasMethodAccess(method, index, opt) && (method.name() == name)) {
1421 QtFunction *fun = new (exec)QtFunction(
1422 object, index, /*maybeOverloaded=*/true,
1423 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1424 propertyName);
1425 unsigned attributes = QObjectMemberAttribute;
1426 if (opt & QScriptEngine::SkipMethodsInEnumeration)
1427 attributes |= JSC::DontEnum;
1428 descriptor.setDescriptor(value: fun, attributes);
1429 data->cachedMembers.insert(key: name, value: fun);
1430 return true;
1431 }
1432 }
1433
1434 if (!(opt & QScriptEngine::ExcludeChildObjects)) {
1435 QList<QObject*> children = qobject->children();
1436 for (index = 0; index < children.count(); ++index) {
1437 QObject *child = children.at(i: index);
1438 if (child->objectName() == QString(propertyName.ustring())) {
1439 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1440 descriptor.setDescriptor(value: eng->newQObject(object: child, ownership: QScriptEngine::QtOwnership, options: opt),
1441 JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum);
1442 return true;
1443 }
1444 }
1445 }
1446
1447 return QScriptObjectDelegate::getOwnPropertyDescriptor(object, exec, propertyName, descriptor);
1448#else //QT_NO_PROPERTIES
1449 return false;
1450#endif //QT_NO_PROPERTIES
1451}
1452
1453void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec,
1454 const JSC::Identifier& propertyName,
1455 JSC::JSValue value, JSC::PutPropertySlot &slot)
1456{
1457#ifndef QT_NO_PROPERTIES
1458 QByteArray name = convertToLatin1(str: propertyName.ustring());
1459 QObject *qobject = data->value;
1460 if (!qobject) {
1461 QString message = QString::fromLatin1(str: "cannot access member `%0' of deleted QObject")
1462 .arg(a: QString::fromLatin1(str: name));
1463 JSC::throwError(exec, JSC::GeneralError, message);
1464 return;
1465 }
1466
1467 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1468 const QMetaObject *meta = qobject->metaObject();
1469 QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
1470 int index = -1;
1471 if (name.contains(c: '(')) {
1472 QByteArray normalized = QMetaObject::normalizedSignature(method: name);
1473 if (-1 != (index = meta->indexOfMethod(method: normalized))) {
1474 QMetaMethod method = meta->method(index);
1475 if (hasMethodAccess(method, index, opt)) {
1476 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1477 || (index >= meta->methodOffset())) {
1478 data->cachedMembers.insert(key: name, value);
1479 return;
1480 }
1481 }
1482 }
1483 }
1484
1485 index = meta->indexOfProperty(name);
1486 if (index != -1) {
1487 QMetaProperty prop = meta->property(index);
1488 if (prop.isScriptable()) {
1489 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1490 || (index >= meta->propertyOffset())) {
1491 if (GeneratePropertyFunctions) {
1492 // ### ideally JSC would do this for us already, i.e. find out
1493 // that the property is a setter and call the setter.
1494 // Maybe QtPropertyFunction needs to inherit JSC::GetterSetter.
1495 JSC::JSValue fun;
1496 QHash<QByteArray, JSC::JSValue>::const_iterator it;
1497 it = data->cachedMembers.constFind(key: name);
1498 if (it != data->cachedMembers.constEnd()) {
1499 fun = it.value();
1500 } else {
1501 fun = new (exec)QtPropertyFunction(
1502 meta, index, &exec->globalData(),
1503 eng->originalGlobalObject()->functionStructure(),
1504 propertyName);
1505 data->cachedMembers.insert(key: name, value: fun);
1506 }
1507 JSC::CallData callData;
1508 JSC::CallType callType = fun.getCallData(callData);
1509 JSC::JSValue argv[1] = { value };
1510 JSC::ArgList args(argv, 1);
1511 (void)JSC::call(exec, functionObject: fun, callType, callData, thisValue: object, args);
1512 } else {
1513 QVariant v;
1514 if (prop.isEnumType() && value.isString()
1515 && !eng->hasDemarshalFunction(type: prop.userType())) {
1516 // give QMetaProperty::write() a chance to convert from
1517 // string to enum value
1518 v = (QString)value.toString(exec);
1519 } else {
1520 v = QScriptEnginePrivate::jscValueToVariant(exec, value, targetType: prop.userType());
1521 }
1522 (void)prop.write(obj: qobject, value: v);
1523 }
1524 return;
1525 }
1526 }
1527 }
1528
1529 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1530 ? meta->methodOffset() : 0;
1531 for (index = meta->methodCount() - 1; index >= offset; --index) {
1532 QMetaMethod method = meta->method(index);
1533 if (hasMethodAccess(method, index, opt) && (method.name() == name)) {
1534 data->cachedMembers.insert(key: name, value);
1535 return;
1536 }
1537 }
1538
1539 index = qobject->dynamicPropertyNames().indexOf(t: name);
1540 if ((index != -1) || (opt & QScriptEngine::AutoCreateDynamicProperties)) {
1541 QVariant v = QScriptEnginePrivate::toVariant(exec, value);
1542 (void)qobject->setProperty(name, value: v);
1543 return;
1544 }
1545
1546 QScriptObjectDelegate::put(object, exec, propertyName, value, slot);
1547#endif //QT_NO_PROPERTIES
1548}
1549
1550bool QObjectDelegate::deleteProperty(QScriptObject *object, JSC::ExecState *exec,
1551 const JSC::Identifier& propertyName)
1552{
1553#ifndef QT_NO_PROPERTIES
1554 QByteArray name = convertToLatin1(str: propertyName.ustring());
1555 QObject *qobject = data->value;
1556 if (!qobject) {
1557 QString message = QString::fromLatin1(str: "cannot access member `%0' of deleted QObject")
1558 .arg(a: QString::fromLatin1(str: name));
1559 JSC::throwError(exec, JSC::GeneralError, message);
1560 return false;
1561 }
1562
1563 const QMetaObject *meta = qobject->metaObject();
1564 {
1565 QHash<QByteArray, JSC::JSValue>::iterator it = data->cachedMembers.find(key: name);
1566 if (it != data->cachedMembers.end()) {
1567 if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
1568 return false;
1569 data->cachedMembers.erase(it);
1570 return true;
1571 }
1572 }
1573
1574 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1575 int index = meta->indexOfProperty(name);
1576 if (index != -1) {
1577 QMetaProperty prop = meta->property(index);
1578 if (prop.isScriptable() &&
1579 (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1580 || (index >= meta->propertyOffset()))) {
1581 return false;
1582 }
1583 }
1584
1585 index = qobject->dynamicPropertyNames().indexOf(t: name);
1586 if (index != -1) {
1587 (void)qobject->setProperty(name, value: QVariant());
1588 return true;
1589 }
1590
1591 return QScriptObjectDelegate::deleteProperty(object, exec, propertyName);
1592#else //QT_NO_PROPERTIES
1593 return false;
1594#endif //QT_NO_PROPERTIES
1595}
1596
1597void QObjectDelegate::getOwnPropertyNames(QScriptObject *object, JSC::ExecState *exec,
1598 JSC::PropertyNameArray &propertyNames,
1599 JSC::EnumerationMode mode)
1600{
1601#ifndef QT_NO_PROPERTIES
1602 QObject *qobject = data->value;
1603 if (!qobject) {
1604 QString message = QString::fromLatin1(str: "cannot get property names of deleted QObject");
1605 JSC::throwError(exec, JSC::GeneralError, message);
1606 return;
1607 }
1608
1609 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1610 const QMetaObject *meta = qobject->metaObject();
1611 {
1612 int i = (opt & QScriptEngine::ExcludeSuperClassProperties)
1613 ? meta->propertyOffset() : 0;
1614 for ( ; i < meta->propertyCount(); ++i) {
1615 QMetaProperty prop = meta->property(index: i);
1616 if (isEnumerableMetaProperty(prop, mo: meta, index: i)) {
1617 QString name = QString::fromLatin1(str: prop.name());
1618 propertyNames.add(JSC::Identifier(exec, name));
1619 }
1620 }
1621 }
1622
1623 {
1624 QList<QByteArray> dpNames = qobject->dynamicPropertyNames();
1625 for (int i = 0; i < dpNames.size(); ++i) {
1626 QString name = QString::fromLatin1(str: dpNames.at(i));
1627 propertyNames.add(JSC::Identifier(exec, name));
1628 }
1629 }
1630
1631 if (!(opt & QScriptEngine::SkipMethodsInEnumeration)) {
1632 int i = (opt & QScriptEngine::ExcludeSuperClassMethods)
1633 ? meta->methodOffset() : 0;
1634 for ( ; i < meta->methodCount(); ++i) {
1635 QMetaMethod method = meta->method(index: i);
1636 if (hasMethodAccess(method, index: i, opt)) {
1637 QMetaMethod method = meta->method(index: i);
1638 QString sig = QString::fromLatin1(str: method.methodSignature().constData());
1639 propertyNames.add(JSC::Identifier(exec, sig));
1640 }
1641 }
1642 }
1643
1644 QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, mode);
1645#endif //QT_NO_PROPERTIES
1646}
1647
1648void QObjectDelegate::markChildren(QScriptObject *object, JSC::MarkStack& markStack)
1649{
1650 QHash<QByteArray, JSC::JSValue>::const_iterator it;
1651 for (it = data->cachedMembers.constBegin(); it != data->cachedMembers.constEnd(); ++it) {
1652 JSC::JSValue val = it.value();
1653 if (val)
1654 markStack.append(value: val);
1655 }
1656
1657 QScriptObjectDelegate::markChildren(object, markStack);
1658}
1659
1660bool QObjectDelegate::compareToObject(QScriptObject *, JSC::ExecState *exec, JSC::JSObject *o2)
1661{
1662 if (!o2->inherits(info: &QScriptObject::info))
1663 return false;
1664 QScriptObject *object = static_cast<QScriptObject*>(o2);
1665 QScriptObjectDelegate *delegate = object->delegate();
1666 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1667 return false;
1668 return value() == static_cast<QObjectDelegate *>(delegate)->value();
1669}
1670
1671static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*,
1672 JSC::JSValue thisValue, const JSC::ArgList &args)
1673{
1674 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1675 thisValue = engine->toUsableValue(value: thisValue);
1676 if (!thisValue.inherits(classInfo: &QScriptObject::info))
1677 return throwError(exec, JSC::TypeError, message: "this object is not a QObject");
1678 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: thisValue));
1679 QScriptObjectDelegate *delegate = scriptObject->delegate();
1680 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1681 return throwError(exec, JSC::TypeError, message: "this object is not a QObject");
1682 QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
1683 QString name;
1684 if (args.size() != 0)
1685 name = args.at(idx: 0).toString(exec);
1686 QObject *child = obj->findChild<QObject*>(aName: name);
1687 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1688 return engine->newQObject(object: child, ownership: QScriptEngine::QtOwnership, options: opt);
1689}
1690
1691static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *exec, JSC::JSObject*,
1692 JSC::JSValue thisValue, const JSC::ArgList &args)
1693{
1694 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1695 thisValue = engine->toUsableValue(value: thisValue);
1696 // extract the QObject
1697 if (!thisValue.inherits(classInfo: &QScriptObject::info))
1698 return throwError(exec, JSC::TypeError, message: "this object is not a QObject");
1699 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: thisValue));
1700 QScriptObjectDelegate *delegate = scriptObject->delegate();
1701 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1702 return throwError(exec, JSC::TypeError, message: "this object is not a QObject");
1703 const QObject *const obj = static_cast<QObjectDelegate*>(delegate)->value();
1704
1705 // find the children
1706 QList<QObject *> children;
1707 if (args.size() != 0) {
1708 const JSC::JSValue arg = args.at(idx: 0);
1709 if (arg.inherits(classInfo: &JSC::RegExpObject::info)) {
1710 const QObjectList allChildren= obj->children();
1711
1712 JSC::RegExpObject *const regexp = JSC::asRegExpObject(value: arg);
1713
1714 const int allChildrenCount = allChildren.size();
1715 for (int i = 0; i < allChildrenCount; ++i) {
1716 QObject *const child = allChildren.at(i);
1717 const JSC::UString childName = child->objectName();
1718 JSC::RegExpConstructor* regExpConstructor = engine->originalGlobalObject()->regExpConstructor();
1719 int position;
1720 int length;
1721 regExpConstructor->performMatch(r: regexp->regExp(), s: childName, startOffset: 0, position, length);
1722 if (position >= 0)
1723 children.append(t: child);
1724 }
1725 } else {
1726 const QString name(args.at(idx: 0).toString(exec));
1727 children = obj->findChildren<QObject*>(aName: name);
1728 }
1729 } else {
1730 children = obj->findChildren<QObject*>(aName: QString());
1731 }
1732 // create the result array with the children
1733 const int length = children.size();
1734 JSC::JSArray *const result = JSC::constructEmptyArray(exec, initialLength: length);
1735
1736 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1737 for (int i = 0; i < length; ++i) {
1738 QObject *const child = children.at(i);
1739 result->put(exec, propertyName: i, engine->newQObject(object: child, ownership: QScriptEngine::QtOwnership, options: opt));
1740 }
1741 return JSC::JSValue(result);
1742}
1743
1744static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*,
1745 JSC::JSValue thisValue, const JSC::ArgList&)
1746{
1747 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1748 thisValue = engine->toUsableValue(value: thisValue);
1749 if (!thisValue.inherits(classInfo: &QScriptObject::info))
1750 return JSC::jsUndefined();
1751 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(value: thisValue));
1752 QScriptObjectDelegate *delegate = scriptObject->delegate();
1753 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1754 return JSC::jsUndefined();
1755 QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
1756 const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
1757 QString name = obj ? obj->objectName() : QString::fromUtf8(str: "unnamed");
1758 QString str = QString::fromUtf8(str: "%0(name = \"%1\")")
1759 .arg(a: QLatin1String(meta->className())).arg(a: name);
1760 return JSC::jsString(exec, s: str);
1761}
1762
1763QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
1764 JSC::Structure* prototypeFunctionStructure)
1765 : QScriptObject(structure)
1766{
1767 setDelegate(new QObjectDelegate(new QObjectPrototypeObject(), QScriptEngine::AutoOwnership,
1768 QScriptEngine::ExcludeSuperClassMethods
1769 | QScriptEngine::ExcludeSuperClassProperties
1770 | QScriptEngine::ExcludeChildObjects));
1771
1772 putDirectFunction(exec, function: new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
1773 putDirectFunction(exec, function: new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
1774 putDirectFunction(exec, function: new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
1775 this->structure()->setHasGetterSetterProperties(true);
1776}
1777
1778const JSC::ClassInfo QMetaObjectWrapperObject::info = { .className: "QMetaObject", .parentClass: 0, .staticPropHashTable: 0, .classPropHashTableGetterFunction: 0 };
1779
1780QMetaObjectWrapperObject::QMetaObjectWrapperObject(
1781 JSC::ExecState *exec, const QMetaObject *metaObject, JSC::JSValue ctor,
1782 WTF::PassRefPtr<JSC::Structure> sid)
1783 : JSC::JSObject(sid),
1784 data(new Data(metaObject, ctor))
1785{
1786 if (!ctor)
1787 data->prototype = new (exec)JSC::JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
1788}
1789
1790QMetaObjectWrapperObject::~QMetaObjectWrapperObject()
1791{
1792 delete data;
1793}
1794
1795bool QMetaObjectWrapperObject::getOwnPropertySlot(
1796 JSC::ExecState *exec, const JSC::Identifier& propertyName,
1797 JSC::PropertySlot &slot)
1798{
1799 const QMetaObject *meta = data->value;
1800 if (!meta)
1801 return false;
1802
1803 if (propertyName == exec->propertyNames().prototype) {
1804 if (data->ctor)
1805 slot.setValue(data->ctor.get(exec, propertyName));
1806 else
1807 slot.setValue(data->prototype);
1808 return true;
1809 }
1810
1811 QByteArray name = convertToLatin1(str: propertyName.ustring());
1812
1813 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1814 QMetaEnum e = meta->enumerator(index: i);
1815 for (int j = 0; j < e.keyCount(); ++j) {
1816 const char *key = e.key(index: j);
1817 if (!qstrcmp(str1: key, str2: name.constData())) {
1818 slot.setValue(JSC::JSValue(exec, e.value(index: j)));
1819 return true;
1820 }
1821 }
1822 }
1823
1824 return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
1825}
1826
1827bool QMetaObjectWrapperObject::getOwnPropertyDescriptor(
1828 JSC::ExecState* exec, const JSC::Identifier& propertyName,
1829 JSC::PropertyDescriptor& descriptor)
1830{
1831 const QMetaObject *meta = data->value;
1832 if (!meta)
1833 return false;
1834
1835 if (propertyName == exec->propertyNames().prototype) {
1836 descriptor.setDescriptor(value: data->ctor
1837 ? data->ctor.get(exec, propertyName)
1838 : data->prototype,
1839 JSC::DontDelete | JSC::DontEnum);
1840 return true;
1841 }
1842
1843 QByteArray name = QString(propertyName.ustring()).toLatin1();
1844
1845 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1846 QMetaEnum e = meta->enumerator(index: i);
1847 for (int j = 0; j < e.keyCount(); ++j) {
1848 const char *key = e.key(index: j);
1849 if (!qstrcmp(str1: key, str2: name.constData())) {
1850 descriptor.setDescriptor(JSC::JSValue(exec, e.value(index: j)),
1851 JSC::ReadOnly | JSC::DontDelete);
1852 return true;
1853 }
1854 }
1855 }
1856
1857 return JSC::JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
1858}
1859
1860void QMetaObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
1861 JSC::JSValue value, JSC::PutPropertySlot &slot)
1862{
1863 if (propertyName == exec->propertyNames().prototype) {
1864 if (data->ctor)
1865 data->ctor.put(exec, propertyName, value, slot);
1866 else
1867 data->prototype = value;
1868 return;
1869 }
1870 const QMetaObject *meta = data->value;
1871 if (meta) {
1872 QByteArray name = convertToLatin1(str: propertyName.ustring());
1873 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1874 QMetaEnum e = meta->enumerator(index: i);
1875 for (int j = 0; j < e.keyCount(); ++j) {
1876 if (!qstrcmp(str1: e.key(index: j), str2: name.constData()))
1877 return;
1878 }
1879 }
1880 }
1881 JSC::JSObject::put(exec, propertyName, value, slot);
1882}
1883
1884bool QMetaObjectWrapperObject::deleteProperty(
1885 JSC::ExecState *exec, const JSC::Identifier& propertyName)
1886{
1887 if (propertyName == exec->propertyNames().prototype)
1888 return false;
1889 const QMetaObject *meta = data->value;
1890 if (meta) {
1891 QByteArray name = convertToLatin1(str: propertyName.ustring());
1892 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1893 QMetaEnum e = meta->enumerator(index: i);
1894 for (int j = 0; j < e.keyCount(); ++j) {
1895 if (!qstrcmp(str1: e.key(index: j), str2: name.constData()))
1896 return false;
1897 }
1898 }
1899 }
1900 return JSC::JSObject::deleteProperty(exec, propertyName);
1901}
1902
1903void QMetaObjectWrapperObject::getOwnPropertyNames(JSC::ExecState *exec,
1904 JSC::PropertyNameArray &propertyNames,
1905 JSC::EnumerationMode mode)
1906{
1907 const QMetaObject *meta = data->value;
1908 if (!meta)
1909 return;
1910 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1911 QMetaEnum e = meta->enumerator(index: i);
1912 for (int j = 0; j < e.keyCount(); ++j)
1913 propertyNames.add(JSC::Identifier(exec, e.key(index: j)));
1914 }
1915 JSC::JSObject::getOwnPropertyNames(exec, propertyNames, mode);
1916}
1917
1918void QMetaObjectWrapperObject::markChildren(JSC::MarkStack& markStack)
1919{
1920 if (data->ctor)
1921 markStack.append(value: data->ctor);
1922 if (data->prototype)
1923 markStack.append(value: data->prototype);
1924 JSC::JSObject::markChildren(markStack);
1925}
1926
1927JSC::CallType QMetaObjectWrapperObject::getCallData(JSC::CallData& callData)
1928{
1929 callData.native.function = call;
1930 return JSC::CallTypeHost;
1931}
1932
1933JSC::ConstructType QMetaObjectWrapperObject::getConstructData(JSC::ConstructData& constructData)
1934{
1935 constructData.native.function = construct;
1936 return JSC::ConstructTypeHost;
1937}
1938
1939JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call(
1940 JSC::ExecState *exec, JSC::JSObject *callee,
1941 JSC::JSValue thisValue, const JSC::ArgList &args)
1942{
1943 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
1944 thisValue = eng_p->toUsableValue(value: thisValue);
1945 if (!callee->inherits(info: &QMetaObjectWrapperObject::info))
1946 return throwError(exec, JSC::TypeError, message: "callee is not a QMetaObject");
1947 QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
1948 JSC::ExecState *previousFrame = eng_p->currentFrame;
1949 eng_p->pushContext(exec, thisObject: thisValue, args, callee);
1950 JSC::JSValue result = self->execute(exec: eng_p->currentFrame, args);
1951 eng_p->popContext();
1952 eng_p->currentFrame = previousFrame;
1953 return result;
1954}
1955
1956JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JSObject *callee, const JSC::ArgList &args)
1957{
1958 QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
1959 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
1960 JSC::ExecState *previousFrame = eng_p->currentFrame;
1961 eng_p->pushContext(exec, JSC::JSValue(), args, callee, calledAsConstructor: true);
1962 JSC::JSValue result = self->execute(exec: eng_p->currentFrame, args);
1963 eng_p->popContext();
1964 eng_p->currentFrame = previousFrame;
1965 if (!result || !result.isObject())
1966 return 0;
1967 return JSC::asObject(value: result);
1968}
1969
1970JSC::JSValue QMetaObjectWrapperObject::execute(JSC::ExecState *exec,
1971 const JSC::ArgList &args)
1972{
1973 if (data->ctor) {
1974 QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
1975 QScriptContext *ctx = eng_p->contextForFrame(frame: exec);
1976 JSC::CallData callData;
1977 JSC::CallType callType = data->ctor.getCallData(callData);
1978 Q_UNUSED(callType);
1979 Q_ASSERT_X(callType == JSC::CallTypeHost, Q_FUNC_INFO, "script constructors not supported");
1980 if (data->ctor.inherits(classInfo: &FunctionWithArgWrapper::info)) {
1981 FunctionWithArgWrapper *wrapper = static_cast<FunctionWithArgWrapper*>(JSC::asObject(value: data->ctor));
1982 QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(d: eng_p), wrapper->arg());
1983 return eng_p->scriptValueToJSCValue(value: result);
1984 } else {
1985 Q_ASSERT(data->ctor.inherits(&FunctionWrapper::info));
1986 FunctionWrapper *wrapper = static_cast<FunctionWrapper*>(JSC::asObject(value: data->ctor));
1987 QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(d: eng_p));
1988 return eng_p->scriptValueToJSCValue(value: result);
1989 }
1990 } else {
1991 const QMetaObject *meta = data->value;
1992 if (meta->constructorCount() > 0) {
1993 JSC::JSValue result = callQtMethod(exec, callType: QMetaMethod::Constructor, /*thisQObject=*/0,
1994 scriptArgs: args, meta, initialIndex: meta->constructorCount()-1, /*maybeOverloaded=*/true);
1995 if (!exec->hadException()) {
1996 Q_ASSERT(result && result.inherits(&QScriptObject::info));
1997 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(value: result));
1998 QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(object->delegate());
1999 delegate->setOwnership(QScriptEngine::AutoOwnership);
2000 if (data->prototype)
2001 object->setPrototype(data->prototype);
2002 }
2003 return result;
2004 } else {
2005 QString message = QString::fromLatin1(str: "no constructor for %0")
2006 .arg(a: QLatin1String(meta->className()));
2007 return JSC::throwError(exec, JSC::TypeError, message);
2008 }
2009 }
2010}
2011
2012struct StaticQtMetaObject : public QObject
2013{
2014 static const QMetaObject *get()
2015 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2016};
2017
2018static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName(
2019 JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&)
2020{
2021 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
2022 thisValue = engine->toUsableValue(value: thisValue);
2023 if (!thisValue.inherits(classInfo: &QMetaObjectWrapperObject::info))
2024 return throwError(exec, JSC::TypeError, message: "this object is not a QMetaObject");
2025 const QMetaObject *meta = static_cast<QMetaObjectWrapperObject*>(JSC::asObject(value: thisValue))->value();
2026 return JSC::jsString(exec, s: meta->className());
2027}
2028
2029QMetaObjectPrototype::QMetaObjectPrototype(
2030 JSC::ExecState *exec, WTF::PassRefPtr<JSC::Structure> structure,
2031 JSC::Structure* prototypeFunctionStructure)
2032 : QMetaObjectWrapperObject(exec, StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
2033{
2034 putDirectFunction(exec, function: new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
2035}
2036
2037// Begin moc-generated code -- modify with care! Check "HAND EDIT" parts
2038struct qt_meta_stringdata_QObjectConnectionManager_t {
2039 QByteArrayData data[3];
2040 char stringdata[44];
2041};
2042#define QT_MOC_LITERAL(idx, ofs, len) { \
2043 Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, \
2044 offsetof(qt_meta_stringdata_QObjectConnectionManager_t, stringdata) + ofs \
2045 - idx * sizeof(QByteArrayData) \
2046 }
2047static const qt_meta_stringdata_QObjectConnectionManager_t qt_meta_stringdata_QObjectConnectionManager = {
2048 .data: {
2049QT_MOC_LITERAL(0, 0, 33),
2050QT_MOC_LITERAL(1, 34, 7),
2051QT_MOC_LITERAL(2, 42, 0)
2052 },
2053 .stringdata: "QScript::QObjectConnectionManager\0"
2054 "execute\0\0"
2055};
2056#undef QT_MOC_LITERAL
2057
2058static const uint qt_meta_data_QObjectConnectionManager[] = {
2059
2060 // content:
2061 7, // revision
2062 0, // classname
2063 0, 0, // classinfo
2064 1, 14, // methods
2065 0, 0, // properties
2066 0, 0, // enums/sets
2067 0, 0, // constructors
2068 0, // flags
2069 0, // signalCount
2070
2071 // slots: name, argc, parameters, tag, flags
2072 1, 0, 19, 2, 0x0a,
2073
2074 // slots: parameters
2075 QMetaType::Void,
2076
2077 0 // eod
2078};
2079
2080void QObjectConnectionManager::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
2081{
2082 if (_c == QMetaObject::InvokeMetaMethod) {
2083 Q_ASSERT(staticMetaObject.cast(_o));
2084 QObjectConnectionManager *_t = static_cast<QObjectConnectionManager *>(_o);
2085 // HAND EDIT: remove switch (_id), add the _id and _a parameters
2086 _t->execute(slotIndex: _id, argv: _a);
2087 }
2088}
2089
2090const QMetaObject QObjectConnectionManager::staticMetaObject = {
2091 .d: { .superdata: &QObject::staticMetaObject, .stringdata: qt_meta_stringdata_QObjectConnectionManager.data,
2092 .data: qt_meta_data_QObjectConnectionManager, .static_metacall: qt_static_metacall, .relatedMetaObjects: 0, .extradata: 0 }
2093};
2094
2095const QMetaObject *QObjectConnectionManager::metaObject() const
2096{
2097 return &staticMetaObject;
2098}
2099
2100void *QObjectConnectionManager::qt_metacast(const char *_clname)
2101{
2102 if (!_clname) return 0;
2103 if (!strcmp(s1: _clname, s2: qt_meta_stringdata_QObjectConnectionManager.stringdata))
2104 return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
2105 return QObject::qt_metacast(_clname);
2106}
2107
2108int QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
2109{
2110 _id = QObject::qt_metacall(_c, _id, _a);
2111 if (_id < 0)
2112 return _id;
2113 if (_c == QMetaObject::InvokeMetaMethod) {
2114 if (_id < slotCounter) // HAND EDIT
2115 qt_static_metacall(o: this, _c, _id, _a);
2116 _id -= slotCounter; // HAND EDIT
2117 }
2118 return _id;
2119}
2120// End moc-generated code
2121
2122void QObjectConnectionManager::execute(int slotIndex, void **argv)
2123{
2124 JSC::JSValue receiver;
2125 JSC::JSValue slot;
2126 JSC::JSValue senderWrapper;
2127 int signalIndex = -1;
2128 QScript::APIShim shim(engine);
2129 for (int i = 0; i < connections.size(); ++i) {
2130 const QVector<QObjectConnection> &cs = connections.at(i);
2131 for (int j = 0; j < cs.size(); ++j) {
2132 const QObjectConnection &c = cs.at(i: j);
2133 if (c.slotIndex == slotIndex) {
2134 receiver = c.receiver;
2135 slot = c.slot;
2136 senderWrapper = c.senderWrapper;
2137 signalIndex = i;
2138 break;
2139 }
2140 }
2141 }
2142 if (!slot) {
2143 // This connection no longer exists (can happen if the signal is
2144 // emitted from another thread and the call gets queued, but the
2145 // connection is removed before the QMetaCallEvent gets processed).
2146 return;
2147 }
2148 Q_ASSERT(slot.isObject());
2149
2150 if (engine->isCollecting()) {
2151 qWarning(msg: "QtScript: can't execute signal handler during GC");
2152 // we can't do a script function call during GC,
2153 // so we're forced to ignore this signal
2154 return;
2155 }
2156
2157#if 0
2158 QScriptFunction *fun = engine->convertToNativeFunction(slot);
2159 if (fun == 0) {
2160 // the signal handler has been GC'ed. This can only happen when
2161 // a QObject is owned by the engine, the engine is destroyed, and
2162 // there is a script function connected to the destroyed() signal
2163 Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
2164 return;
2165 }
2166#endif
2167
2168 const QMetaObject *meta = sender()->metaObject();
2169 const QMetaMethod method = meta->method(index: signalIndex);
2170
2171 QList<QByteArray> parameterTypes = method.parameterTypes();
2172 int argc = parameterTypes.count();
2173
2174 JSC::ExecState *exec = engine->currentFrame;
2175 QVarLengthArray<JSC::JSValue, 8> argsVector(argc);
2176 for (int i = 0; i < argc; ++i) {
2177 JSC::JSValue actual;
2178 void *arg = argv[i + 1];
2179 QByteArray typeName = parameterTypes.at(i);
2180 int argType = QMetaType::type(typeName: parameterTypes.at(i));
2181 if (!argType) {
2182 qWarning(msg: "QScriptEngine: Unable to handle unregistered datatype '%s' "
2183 "when invoking handler of signal %s::%s",
2184 typeName.constData(), meta->className(), method.methodSignature().constData());
2185 actual = JSC::jsUndefined();
2186 } else if (argType == QMetaType::QVariant) {
2187 actual = QScriptEnginePrivate::jscValueFromVariant(exec, v: *reinterpret_cast<QVariant*>(arg));
2188 } else {
2189 actual = QScriptEnginePrivate::create(exec, type: argType, ptr: arg);
2190 }
2191 argsVector[i] = actual;
2192 }
2193 JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
2194
2195 JSC::JSValue senderObject;
2196 if (senderWrapper && senderWrapper.inherits(classInfo: &QScriptObject::info)) // ### check if it's actually a QObject wrapper
2197 senderObject = senderWrapper;
2198 else {
2199 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
2200 senderObject = engine->newQObject(object: sender(), ownership: QScriptEngine::QtOwnership, options: opt);
2201 }
2202
2203 JSC::JSValue thisObject;
2204 if (receiver && receiver.isObject())
2205 thisObject = receiver;
2206 else
2207 thisObject = engine->globalObject();
2208
2209 JSC::CallData callData;
2210 JSC::CallType callType = slot.getCallData(callData);
2211 if (exec->hadException())
2212 exec->clearException(); // ### otherwise JSC asserts
2213 JSC::call(exec, functionObject: slot, callType, callData, thisValue: thisObject, jscArgs);
2214
2215 if (exec->hadException()) {
2216 if (slot.inherits(classInfo: &QtFunction::info) && !static_cast<QtFunction*>(JSC::asObject(value: slot))->qobject()) {
2217 // The function threw an error because the target QObject has been deleted.
2218 // The connections list is stale; remove the signal handler and ignore the exception.
2219 removeSignalHandler(sender: sender(), signalIndex, receiver, slot);
2220 exec->clearException();
2221 } else {
2222 engine->emitSignalHandlerException();
2223 }
2224 }
2225}
2226
2227QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
2228 : engine(eng), slotCounter(0)
2229{
2230}
2231
2232QObjectConnectionManager::~QObjectConnectionManager()
2233{
2234}
2235
2236void QObjectConnectionManager::clearMarkBits()
2237{
2238 for (int i = 0; i < connections.size(); ++i) {
2239 QVector<QObjectConnection> &cs = connections[i];
2240 for (int j = 0; j < cs.size(); ++j)
2241 cs[j].marked = false;
2242 }
2243}
2244
2245/*!
2246 \internal
2247
2248 Marks connections owned by this manager.
2249 Returns the number of connections that were marked by this pass
2250 (i.e., excluding connections that were already marked).
2251*/
2252int QObjectConnectionManager::mark(JSC::MarkStack& markStack)
2253{
2254 int markedCount = 0;
2255 for (int i = 0; i < connections.size(); ++i) {
2256 QVector<QObjectConnection> &cs = connections[i];
2257 for (int j = 0; j < cs.size(); ++j) {
2258 QObjectConnection &c = cs[j];
2259 if (!c.marked) {
2260 if (c.hasWeaklyReferencedSender()) {
2261 // Don't mark the connection; we don't want the script-owned
2262 // sender object to stay alive merely due to a connection.
2263 } else {
2264 c.mark(markStack);
2265 ++markedCount;
2266 }
2267 }
2268 }
2269 }
2270 return markedCount;
2271}
2272
2273bool QObjectConnectionManager::addSignalHandler(
2274 QObject *sender, int signalIndex, JSC::JSValue receiver,
2275 JSC::JSValue function, JSC::JSValue senderWrapper,
2276 Qt::ConnectionType type)
2277{
2278 if (connections.size() <= signalIndex)
2279 connections.resize(size: signalIndex+1);
2280 QVector<QObjectConnection> &cs = connections[signalIndex];
2281 int absSlotIndex = slotCounter + metaObject()->methodOffset();
2282 bool ok = QMetaObject::connect(sender, signal_index: signalIndex, receiver: this, method_index: absSlotIndex, type);
2283 if (ok)
2284 cs.append(t: QObjectConnection(slotCounter++, receiver, function, senderWrapper));
2285 return ok;
2286}
2287
2288bool QObjectConnectionManager::removeSignalHandler(
2289 QObject *sender, int signalIndex,
2290 JSC::JSValue receiver, JSC::JSValue slot)
2291{
2292 if (connections.size() <= signalIndex)
2293 return false;
2294 QVector<QObjectConnection> &cs = connections[signalIndex];
2295 for (int i = 0; i < cs.size(); ++i) {
2296 const QObjectConnection &c = cs.at(i);
2297 if (c.hasTarget(r: receiver, s: slot)) {
2298 int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
2299 bool ok = QMetaObject::disconnect(sender, signal_index: signalIndex, receiver: this, method_index: absSlotIndex);
2300 if (ok)
2301 cs.remove(i);
2302 return ok;
2303 }
2304 }
2305 return false;
2306}
2307
2308QObjectData::QObjectData(QScriptEnginePrivate *eng)
2309 : engine(eng), connectionManager(0)
2310{
2311}
2312
2313QObjectData::~QObjectData()
2314{
2315 if (connectionManager) {
2316 delete connectionManager;
2317 connectionManager = 0;
2318 }
2319}
2320
2321void QObjectData::clearConnectionMarkBits()
2322{
2323 if (connectionManager)
2324 connectionManager->clearMarkBits();
2325}
2326
2327int QObjectData::markConnections(JSC::MarkStack& markStack)
2328{
2329 if (connectionManager)
2330 return connectionManager->mark(markStack);
2331 return 0;
2332}
2333
2334// This function assumes all objects reachable elsewhere in the JS environment
2335// (stack, heap) have been marked already (see QScriptEnginePrivate::mark()).
2336// This determines whether any of Qt Script's internal QObject wrappers are only
2337// weakly referenced and can be discarded.
2338void QObjectData::markWrappers(JSC::MarkStack& markStack)
2339{
2340 QList<QScript::QObjectWrapperInfo>::iterator it;
2341 for (it = wrappers.begin(); it != wrappers.end(); ) {
2342 const QScript::QObjectWrapperInfo &info = *it;
2343 if (JSC::Heap::isCellMarked(cell: info.object)) {
2344 ++it;
2345 } else if (info.isCollectableWhenWeaklyReferenced()) {
2346 it = wrappers.erase(pos: it);
2347 } else {
2348 markStack.append(cell: info.object);
2349 ++it;
2350 }
2351 }
2352}
2353
2354bool QObjectData::addSignalHandler(QObject *sender,
2355 int signalIndex,
2356 JSC::JSValue receiver,
2357 JSC::JSValue slot,
2358 JSC::JSValue senderWrapper,
2359 Qt::ConnectionType type)
2360{
2361 if (!connectionManager)
2362 connectionManager = new QObjectConnectionManager(engine);
2363 return connectionManager->addSignalHandler(
2364 sender, signalIndex, receiver, function: slot, senderWrapper, type);
2365}
2366
2367bool QObjectData::removeSignalHandler(QObject *sender,
2368 int signalIndex,
2369 JSC::JSValue receiver,
2370 JSC::JSValue slot)
2371{
2372 if (!connectionManager)
2373 return false;
2374 return connectionManager->removeSignalHandler(
2375 sender, signalIndex, receiver, slot);
2376}
2377
2378QScriptObject *QObjectData::findWrapper(QScriptEngine::ValueOwnership ownership,
2379 const QScriptEngine::QObjectWrapOptions &options) const
2380{
2381 for (int i = 0; i < wrappers.size(); ++i) {
2382 const QObjectWrapperInfo &info = wrappers.at(i);
2383 if ((info.ownership == ownership) && (info.options == options))
2384 return info.object;
2385 }
2386 return 0;
2387}
2388
2389void QObjectData::registerWrapper(QScriptObject *wrapper,
2390 QScriptEngine::ValueOwnership ownership,
2391 const QScriptEngine::QObjectWrapOptions &options)
2392{
2393 wrappers.append(t: QObjectWrapperInfo(wrapper, ownership, options));
2394}
2395
2396} // namespace QScript
2397
2398QT_END_NAMESPACE
2399
2400namespace JSC
2401{
2402 ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
2403}
2404
2405#include "moc_qscriptqobject_p.cpp"
2406
2407

source code of qtscript/src/script/bridge/qscriptqobject.cpp