1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
46 // This file is not part of the Qt API. It exists purely as an
47 // implementation detail. This header file may change from version to
48 // version without notice, or even be removed.
53 #ifndef QJSVALUE_IMPL_P_H
54 #define QJSVALUE_IMPL_P_H
56 #include "qjsconverter_p.h"
57 #include "qjsvalue_p.h"
58 #include "qv8engine_p.h"
59 #include "qscriptisolate_p.h"
63 QJSValuePrivate* QJSValuePrivate::get(const QJSValue& q) { Q_ASSERT(q.d_ptr.data()); return q.d_ptr.data(); }
65 QJSValue QJSValuePrivate::get(const QJSValuePrivate* d)
68 return QJSValue(const_cast<QJSValuePrivate*>(d));
71 QJSValue QJSValuePrivate::get(QScriptPassPointer<QJSValuePrivate> d)
77 QJSValue QJSValuePrivate::get(QJSValuePrivate* d)
83 QJSValuePrivate::QJSValuePrivate(bool value)
84 : m_engine(0), m_state(CBool), u(value)
88 QJSValuePrivate::QJSValuePrivate(int value)
89 : m_engine(0), m_state(CNumber), u(value)
93 QJSValuePrivate::QJSValuePrivate(uint value)
94 : m_engine(0), m_state(CNumber), u(value)
98 QJSValuePrivate::QJSValuePrivate(double value)
99 : m_engine(0), m_state(CNumber), u(value)
103 QJSValuePrivate::QJSValuePrivate(const QString& value)
104 : m_engine(0), m_state(CString), u(new QString(value))
108 QJSValuePrivate::QJSValuePrivate(QJSValue::SpecialValue value)
109 : m_engine(0), m_state(value == QJSValue::NullValue ? CNull : CUndefined)
113 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, bool value)
114 : m_engine(engine), m_state(JSValue)
117 v8::HandleScope handleScope;
118 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
119 m_engine->registerValue(this);
122 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, int value)
123 : m_engine(engine), m_state(JSValue)
126 v8::HandleScope handleScope;
127 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
128 m_engine->registerValue(this);
131 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, uint value)
132 : m_engine(engine), m_state(JSValue)
135 v8::HandleScope handleScope;
136 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
137 m_engine->registerValue(this);
140 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, double value)
141 : m_engine(engine), m_state(JSValue)
144 v8::HandleScope handleScope;
145 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
146 m_engine->registerValue(this);
149 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, const QString& value)
150 : m_engine(engine), m_state(JSValue)
153 v8::HandleScope handleScope;
154 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
155 m_engine->registerValue(this);
158 QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, QJSValue::SpecialValue value)
159 : m_engine(engine), m_state(JSValue)
162 v8::HandleScope handleScope;
163 m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
164 m_engine->registerValue(this);
167 QJSValuePrivate::QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value> value)
168 : m_engine(engine), m_state(JSValue), m_value(v8::Persistent<v8::Value>::New(value))
171 // It shouldn't happen, v8 shows errors by returning an empty handler. This is important debug
172 // information and it can't be simply ignored.
173 Q_ASSERT(!value.IsEmpty());
174 m_engine->registerValue(this);
177 QJSValuePrivate::~QJSValuePrivate()
180 m_engine->unregisterValue(this);
181 QScriptIsolate api(m_engine);
183 } else if (isStringBased()) {
188 bool QJSValuePrivate::toBool() const
193 v8::HandleScope scope;
194 return m_value->ToBoolean()->Value();
197 return !(qIsNaN(u.m_number) || !u.m_number);
204 return u.m_string->length();
207 Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
208 return false; // Avoid compiler warning.
211 double QJSValuePrivate::toNumber() const
216 v8::HandleScope scope;
217 return m_value->ToNumber()->Value();
222 return u.m_bool ? 1 : 0;
228 double result = u.m_string->toDouble(&ok);
231 result = u.m_string->toInt(&ok, 0); // Try other bases.
234 if (*u.m_string == QLatin1String("Infinity"))
236 if (*u.m_string == QLatin1String("-Infinity"))
238 return u.m_string->length() ? qQNaN() : 0;
241 Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
242 return 0; // Avoid compiler warning.
245 QString QJSValuePrivate::toString() const
249 return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false");
253 return QJSConverter::toString(u.m_number);
255 return QString::fromLatin1("null");
257 return QString::fromLatin1("undefined");
259 Q_ASSERT(!m_value.IsEmpty());
260 v8::HandleScope handleScope;
261 v8::TryCatch tryCatch;
262 v8::Local<v8::String> result = m_value->ToString();
263 if (result.IsEmpty())
264 result = tryCatch.Exception()->ToString();
265 return QJSConverter::toString(result);
268 Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
269 return QString(); // Avoid compiler warning.
272 QVariant QJSValuePrivate::toVariant() const
276 return QVariant(u.m_bool);
278 return QVariant(*u.m_string);
280 return QVariant(u.m_number);
282 return QVariant(QMetaType::VoidStar, 0);
289 Q_ASSERT(m_state == JSValue);
290 Q_ASSERT(!m_value.IsEmpty());
293 v8::HandleScope handleScope;
294 return m_engine->variantFromJS(m_value);
297 inline QDateTime QJSValuePrivate::toDataTime() const
302 v8::HandleScope handleScope;
303 return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(m_value));
307 QObject* QJSValuePrivate::toQObject() const
312 v8::HandleScope handleScope;
313 return engine()->qtObjectFromJS(m_value);
316 double QJSValuePrivate::toInteger() const
318 double result = toNumber();
324 // Must use floor explicitly rather than qFloor here. On some
325 // platforms qFloor will cast the value to a single precision float and use
326 // floorf() which results in test failures.
327 return (result > 0) ? floor(result) : -1 * floor(-result);
330 qint32 QJSValuePrivate::toInt32() const
332 double result = toInteger();
333 // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
334 // some of these operation are invoked in toInteger subcall.
340 quint32 QJSValuePrivate::toUInt32() const
342 double result = toInteger();
343 // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
344 // some of these operation are invoked in toInteger subcall.
348 // The explicit casts are required to avoid undefined behaviour. For example, casting
349 // a negative double directly to an unsigned int on ARM NEON FPU results in the value
350 // being set to zero. Casting to a signed int first ensures well defined behaviour.
351 return (quint32) (qint32) result;
354 quint16 QJSValuePrivate::toUInt16() const
359 inline bool QJSValuePrivate::isArray() const
361 return isJSBased() && m_value->IsArray();
364 inline bool QJSValuePrivate::isBool() const
366 return m_state == CBool || (isJSBased() && m_value->IsBoolean());
369 inline bool QJSValuePrivate::isCallable() const
374 // Our C++ wrappers register function handlers but not always act as callables.
375 return v8::Object::Cast(*m_value)->IsCallable();
380 inline bool QJSValuePrivate::isError() const
384 v8::HandleScope handleScope;
385 return m_value->IsError();
388 inline bool QJSValuePrivate::isFunction() const
390 return isJSBased() && m_value->IsFunction();
393 inline bool QJSValuePrivate::isNull() const
395 return m_state == CNull || (isJSBased() && m_value->IsNull());
398 inline bool QJSValuePrivate::isNumber() const
400 return m_state == CNumber || (isJSBased() && m_value->IsNumber());
403 inline bool QJSValuePrivate::isObject() const
405 return isJSBased() && m_value->IsObject();
408 inline bool QJSValuePrivate::isString() const
410 return m_state == CString || (isJSBased() && m_value->IsString());
413 inline bool QJSValuePrivate::isUndefined() const
415 return m_state == CUndefined || (isJSBased() && m_value->IsUndefined());
418 inline bool QJSValuePrivate::isVariant() const
420 return isJSBased() && m_engine->isVariant(m_value);
423 bool QJSValuePrivate::isDate() const
425 return (isJSBased() && m_value->IsDate());
428 bool QJSValuePrivate::isRegExp() const
430 return (isJSBased() && m_value->IsRegExp());
433 bool QJSValuePrivate::isQObject() const
435 return isJSBased() && engine()->isQObject(m_value);
438 inline bool QJSValuePrivate::equals(QJSValuePrivate* other)
440 if (!isJSBased() && !other->isJSBased()) {
444 return other->isUndefined() || other->isNull();
446 switch (other->m_state) {
449 return u.m_number == other->toNumber();
451 return u.m_number == other->u.m_number;
456 switch (other->m_state) {
458 return u.m_bool == other->u.m_bool;
460 return toNumber() == other->u.m_number;
462 return toNumber() == other->toNumber();
467 switch (other->m_state) {
469 return toNumber() == other->toNumber();
471 return toNumber() == other->u.m_number;
473 return *u.m_string == *other->u.m_string;
478 Q_ASSERT_X(false, "QJSValue::equals", "Not all states are included in the previous switch statement.");
482 v8::HandleScope handleScope;
483 if (isJSBased() && !other->isJSBased()) {
484 if (!other->assignEngine(engine())) {
485 qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
488 } else if (!isJSBased() && other->isJSBased()) {
489 if (!assignEngine(other->engine())) {
490 qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
495 Q_ASSERT(this->engine() && other->engine());
496 if (this->engine() != other->engine()) {
497 qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
500 return m_value->Equals(other->m_value);
503 inline bool QJSValuePrivate::strictlyEquals(QJSValuePrivate* other)
506 // We can't compare these two values without binding to the same engine.
507 if (!other->isJSBased()) {
508 if (other->assignEngine(engine()))
509 return m_value->StrictEquals(other->m_value);
512 if (other->engine() != engine()) {
513 qWarning("QJSValue::strictlyEquals: cannot compare to a value created in a different engine");
516 return m_value->StrictEquals(other->m_value);
518 if (isStringBased()) {
519 if (other->isStringBased())
520 return *u.m_string == *(other->u.m_string);
521 if (other->isJSBased()) {
522 assignEngine(other->engine());
523 return m_value->StrictEquals(other->m_value);
526 if (isNumberBased()) {
527 if (other->isJSBased()) {
528 assignEngine(other->engine());
529 return m_value->StrictEquals(other->m_value);
531 if (m_state != other->m_state)
533 if (m_state == CNumber)
534 return u.m_number == other->u.m_number;
535 Q_ASSERT(m_state == CBool);
536 return u.m_bool == other->u.m_bool;
539 return (isUndefined() && other->isUndefined())
540 || (isNull() && other->isNull());
543 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::prototype() const
546 v8::HandleScope handleScope;
547 return new QJSValuePrivate(engine(), v8::Handle<v8::Object>::Cast(m_value)->GetPrototype());
549 return new QJSValuePrivate();
552 inline void QJSValuePrivate::setPrototype(QJSValuePrivate* prototype)
554 if (isObject() && (prototype->isObject() || prototype->isNull())) {
555 if (engine() != prototype->engine()) {
556 if (prototype->engine()) {
557 qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
560 prototype->assignEngine(engine());
562 v8::HandleScope handleScope;
563 if (!v8::Handle<v8::Object>::Cast(m_value)->SetPrototype(*prototype))
564 qWarning("QJSValue::setPrototype() failed: cyclic prototype value");
568 inline void QJSValuePrivate::setProperty(const QString& name, QJSValuePrivate* value, uint attribs)
572 v8::HandleScope handleScope;
573 setProperty(QJSConverter::toString(name), value, attribs);
576 inline void QJSValuePrivate::setProperty(v8::Handle<v8::String> name, QJSValuePrivate* value, uint attribs)
581 if (!value->isJSBased())
582 value->assignEngine(engine());
584 if (engine() != value->engine()) {
585 qWarning("QJSValue::setProperty(%s) failed: "
586 "cannot set value created in a different engine",
587 qPrintable(QJSConverter::toString(name)));
591 v8::TryCatch tryCatch;
592 // if (attribs & (QJSValue::PropertyGetter | QJSValue::PropertySetter)) {
593 // engine()->originalGlobalObject()->defineGetterOrSetter(*this, name, value->m_value, attribs);
595 v8::Object::Cast(*m_value)->Set(name, value->m_value, v8::PropertyAttribute(attribs & QJSConverter::PropertyAttributeMask));
599 inline void QJSValuePrivate::setProperty(quint32 index, QJSValuePrivate* value, uint attribs)
601 // FIXME this method should by integrated with other overloads to use the same code patch.
602 // for now it is not possible as v8 doesn't allow to set property attributes using index based api.
608 // FIXME we don't need to convert index to a string.
609 //Object::Set(int,value) do not take attributes.
610 setProperty(QString::number(index), value, attribs);
614 if (!value->isJSBased())
615 value->assignEngine(engine());
617 if (engine() != value->engine()) {
618 qWarning("QJSValue::setProperty() failed: cannot set value created in a different engine");
622 v8::HandleScope handleScope;
623 v8::Object::Cast(*m_value)->Set(index, value->m_value);
626 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(const QString& name) const
629 return new QJSValuePrivate();
631 return new QJSValuePrivate(engine());
633 v8::HandleScope handleScope;
634 return property(QJSConverter::toString(name));
637 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(v8::Handle<v8::String> name) const
639 Q_ASSERT(!name.IsEmpty());
641 return new QJSValuePrivate();
642 return property<>(name);
645 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(quint32 index) const
648 return new QJSValuePrivate();
649 return property<>(index);
653 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(T name) const
655 Q_ASSERT(isObject());
656 v8::HandleScope handleScope;
657 v8::Handle<v8::Object> self(v8::Object::Cast(*m_value));
659 v8::TryCatch tryCatch;
660 v8::Handle<v8::Value> result = self->Get(name);
661 if (tryCatch.HasCaught())
662 result = tryCatch.Exception();
663 if (result.IsEmpty())
664 return new QJSValuePrivate(engine());
665 return new QJSValuePrivate(engine(), result);
668 inline bool QJSValuePrivate::deleteProperty(const QString& name)
673 v8::HandleScope handleScope;
674 v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
675 return self->Delete(QJSConverter::toString(name));
678 inline bool QJSValuePrivate::hasProperty(const QString &name) const
683 v8::HandleScope handleScope;
684 v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
685 return self->Has(QJSConverter::toString(name));
688 inline bool QJSValuePrivate::hasOwnProperty(const QString &name) const
693 v8::HandleScope handleScope;
694 v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
695 return self->HasOwnProperty(QJSConverter::toString(name));
698 inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(const QString& name) const
701 return QJSValuePrivate::PropertyFlags(0);
703 v8::HandleScope handleScope;
704 return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), QJSConverter::toString(name));
707 inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(v8::Handle<v8::String> name) const
710 return QJSValuePrivate::PropertyFlags(0);
712 v8::HandleScope handleScope;
713 return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), name);
716 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, const QJSValueList& args)
719 return new QJSValuePrivate();
721 v8::HandleScope handleScope;
723 // Convert all arguments and bind to the engine.
724 int argc = args.size();
725 QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
726 if (!prepareArgumentsForCall(argv.data(), args)) {
727 qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
728 return new QJSValuePrivate(engine());
731 return call(thisObject, argc, argv.data());
734 QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, int argc, v8::Handle<v8::Value> *argv)
736 QV8Engine *e = engine();
738 v8::Handle<v8::Object> recv;
740 if (!thisObject || !thisObject->isObject()) {
741 recv = v8::Handle<v8::Object>(v8::Object::Cast(*e->global()));
743 if (!thisObject->assignEngine(e)) {
744 qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine");
745 return new QJSValuePrivate(engine());
748 recv = v8::Handle<v8::Object>(v8::Object::Cast(*thisObject->m_value));
752 v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
753 return new QJSValuePrivate(e, exeption);
756 v8::TryCatch tryCatch;
757 v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsFunction(recv, argc, argv);
759 if (result.IsEmpty()) {
760 result = tryCatch.Exception();
761 // TODO: figure out why v8 doesn't always produce an exception value.
762 //Q_ASSERT(!result.IsEmpty());
763 if (result.IsEmpty())
764 result = v8::Exception::Error(v8::String::New("missing exception value"));
767 return new QJSValuePrivate(e, result);
770 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(int argc, v8::Handle<v8::Value> *argv)
772 QV8Engine *e = engine();
775 v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
776 return new QJSValuePrivate(e, exeption);
779 v8::TryCatch tryCatch;
780 v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsConstructor(argc, argv);
782 if (result.IsEmpty())
783 result = tryCatch.Exception();
785 return new QJSValuePrivate(e, result);
788 inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(const QJSValueList& args)
791 return new QJSValuePrivate();
793 v8::HandleScope handleScope;
795 // Convert all arguments and bind to the engine.
796 int argc = args.size();
797 QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
798 if (!prepareArgumentsForCall(argv.data(), args)) {
799 qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
800 return new QJSValuePrivate(engine());
803 return callAsConstructor(argc, argv.data());
807 * Make sure this value is associated with a v8 value belonging to this engine.
808 * If the value belongs to another engine, returns false.
810 bool QJSValuePrivate::assignEngine(QV8Engine* engine)
813 v8::HandleScope handleScope;
816 m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_bool));
819 m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(*u.m_string));
823 m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_number));
826 m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::NullValue));
829 m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::UndefinedValue));
832 if (this->engine() == engine)
834 else if (!isJSBased())
835 Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
837 qWarning("JSValue can't be rassigned to an another engine.");
843 m_engine->registerValue(this);
849 Invalidates this value (makes it undefined).
851 Does not remove the value from the engine's list of
852 registered values; that's the responsibility of the caller.
854 void QJSValuePrivate::invalidate()
859 } else if (isStringBased()) {
863 m_state = CUndefined;
866 QV8Engine* QJSValuePrivate::engine() const
871 inline QJSValuePrivate::operator v8::Handle<v8::Value>() const
873 Q_ASSERT(isJSBased());
877 inline QJSValuePrivate::operator v8::Handle<v8::Object>() const
879 Q_ASSERT(isObject());
880 return v8::Handle<v8::Object>::Cast(m_value);
883 inline v8::Handle<v8::Value> QJSValuePrivate::handle() const
889 * Return a v8::Handle, assign to the engine if needed.
891 v8::Handle<v8::Value> QJSValuePrivate::asV8Value(QV8Engine* engine)
894 if (!assignEngine(engine))
895 return v8::Handle<v8::Value>();
897 Q_ASSERT(isJSBased());
903 Returns true if QSV have an engine associated.
905 bool QJSValuePrivate::isJSBased() const
909 if (m_state >= JSValue)
910 Q_ASSERT(!m_value.IsEmpty());
912 Q_ASSERT(m_value.IsEmpty());
914 return m_state >= JSValue;
919 Returns true if current value of QSV is placed in m_number.
921 bool QJSValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; }
925 Returns true if current value of QSV is placed in m_string.
927 bool QJSValuePrivate::isStringBased() const { return m_state == CString; }
931 Converts arguments and bind them to the engine.
932 \attention argv should be big enough
934 inline bool QJSValuePrivate::prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& args) const
936 QJSValueList::const_iterator i = args.constBegin();
937 for (int j = 0; i != args.constEnd(); j++, i++) {
938 QJSValuePrivate* value = QJSValuePrivate::get(*i);
939 if ((value->isJSBased() && engine() != value->engine())
940 || (!value->isJSBased() && !value->assignEngine(engine())))
941 // Different engines are not allowed!