120QJSManagedValue::QJSManagedValue(QJSValue value, QJSEngine *engine)
122 QV4::ExecutionEngine *v4 = engine->handle();
124 if (QV4::Value *m = QJSValuePrivate::takeManagedValue(&value)) {
125 if (Q_UNLIKELY(v4Engine(m) != v4)) {
126 qWarning(
"QJSManagedValue(QJSValue, QJSEngine *) failed: "
127 "Value was created in different engine.");
128 QV4::PersistentValueStorage::free(m);
136 d = v4->memoryManager->m_persistentValues->allocate();
138 if (
const QString *string = QJSValuePrivate::asQString(&value))
139 *d = v4->newString(*string);
141 *d = QJSValuePrivate::asReturnedValue(&value);
147QJSManagedValue::QJSManagedValue(
const QJSPrimitiveValue &value, QJSEngine *engine) :
148 QJSManagedValue(engine->handle())
150 switch (value.type()) {
151 case QJSPrimitiveValue::Undefined:
152 *d = QV4::Encode::undefined();
154 case QJSPrimitiveValue::Null:
155 *d = QV4::Encode::null();
157 case QJSPrimitiveValue::Boolean:
158 *d = QV4::Encode(value.asBoolean());
160 case QJSPrimitiveValue::Integer:
161 *d = QV4::Encode(value.asInteger());
163 case QJSPrimitiveValue::Double:
164 *d = QV4::Encode(value.asDouble());
166 case QJSPrimitiveValue::String:
167 *d = engine->handle()->newString(value.asString());
177QJSManagedValue::QJSManagedValue(
const QVariant &variant, QJSEngine *engine) :
178 QJSManagedValue(engine->handle())
180 *d = engine->handle()->fromVariant(variant);
186QJSManagedValue::QJSManagedValue(
const QString &string, QJSEngine *engine) :
187 QJSManagedValue(engine->handle())
189 *d = engine->handle()->newString(string);
284QJSManagedValue QJSManagedValue::prototype()
const
287 return QJSManagedValue();
289 QV4::ExecutionEngine *v4 = v4Engine(d);
290 QJSManagedValue result(v4);
292 if (
auto object = d->as<QV4::Object>())
293 *result.d = object->getPrototypeOf();
294 else if (
auto managed = d->as<QV4::Managed>())
295 *result.d = managed->internalClass()->prototype;
296 else if (d->isBoolean())
297 *result.d = v4->booleanPrototype();
298 else if (d->isNumber())
299 *result.d = v4->numberPrototype();
302 if (result.d->isUndefined())
303 *result.d = QV4::Encode::null();
314void QJSManagedValue::setPrototype(
const QJSManagedValue &prototype)
316 auto object = d ? d->as<QV4::Object>() :
nullptr;
318 qWarning(
"QJSManagedValue::setPrototype() failed: "
319 "Can only set a prototype on an object (excluding null).");
324 if (prototype.type() != QJSManagedValue::Object) {
325 qWarning(
"QJSManagedValue::setPrototype() failed: "
326 "Can only set objects (including null) as prototypes.");
330 if (Q_UNLIKELY(object->engine() != v4Engine(prototype.d))) {
331 qWarning(
"QJSManagedValue::setPrototype() failed: "
332 "Prototype was created in differen engine.");
337 if (!object->setPrototypeOf(prototype.d->as<QV4::Object>())) {
338 qWarning(
"QJSManagedValue::setPrototype() failed: "
339 "Prototype cycle detected.");
621QVariant QJSManagedValue::toVariant()
const
623 if (!d || d->isUndefined())
626 return QVariant(QMetaType::fromType<std::nullptr_t>(),
nullptr);
628 return QVariant(d->booleanValue());
630 return QVariant(d->integerValue());
632 return QVariant(d->doubleValue());
634 return QVariant(d->toQString());
635 if (d->as<QV4::Managed>())
636 return QV4::ExecutionEngine::toVariant(*d, QMetaType{},
true);
638 Q_UNREACHABLE_RETURN(QVariant());
700bool QJSManagedValue::hasProperty(
const QString &name)
const
702 if (!d || d->isNullOrUndefined())
705 if (d->isString() && name == QStringLiteral(
"length"))
708 if (QV4::Object *obj = d->as<QV4::Object>()) {
709 QV4::Scope scope(obj->engine());
710 QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
711 return obj->hasProperty(key);
714 return prototype().hasProperty(name);
721bool QJSManagedValue::hasOwnProperty(
const QString &name)
const
723 if (!d || d->isNullOrUndefined())
726 if (d->isString() && name == QStringLiteral(
"length"))
729 if (QV4::Object *obj = d->as<QV4::Object>()) {
730 QV4::Scope scope(obj->engine());
731 QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
732 return obj->getOwnProperty(key) != QV4::Attr_Invalid;
742QJSValue QJSManagedValue::property(
const QString &name)
const
747 if (d->isNullOrUndefined()) {
748 QV4::ExecutionEngine *e = v4Engine(d);
749 e->throwTypeError(QStringLiteral(
"Cannot read property '%1' of null").arg(name));
753 if (QV4::String *string = d->as<QV4::String>()) {
754 if (name == QStringLiteral(
"length"))
755 return QJSValue(string->d()->length());
758 if (QV4::Object *obj = d->as<QV4::Object>()) {
759 QV4::Scope scope(obj->engine());
760 QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
761 return QJSValuePrivate::fromReturnedValue(obj->get(key));
764 return prototype().property(name);
772void QJSManagedValue::setProperty(
const QString &name,
const QJSValue &value)
777 if (d->isNullOrUndefined()) {
778 v4Engine(d)->throwTypeError(
779 QStringLiteral(
"Value is null and could not be converted to an object"));
782 if (QV4::Object *obj = d->as<QV4::Object>()) {
783 QV4::Scope scope(obj->engine());
784 QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
785 if (Q_UNLIKELY(v4 && v4 != scope.engine)) {
786 qWarning(
"QJSManagedValue::setProperty() failed: "
787 "Value was created in different engine.");
790 QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
791 QV4::ScopedValue val(scope, QJSValuePrivate::convertToReturnedValue(scope.engine, value));
800bool QJSManagedValue::deleteProperty(
const QString &name)
805 if (QV4::Object *obj = d->as<QV4::Object>()) {
806 QV4::Scope scope(obj->engine());
807 QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
808 return obj->deleteProperty(key);
819bool QJSManagedValue::hasProperty(quint32 arrayIndex)
const
821 if (!d || d->isNullOrUndefined())
824 if (QV4::String *string = d->as<QV4::String>())
825 return arrayIndex < quint32(string->d()->length());
827 if (QV4::Object *obj = d->as<QV4::Object>()) {
828 bool hasProperty =
false;
829 if (arrayIndex == std::numeric_limits<quint32>::max())
830 obj->get(obj->engine()->id_uintMax(), &hasProperty);
832 obj->get(arrayIndex, &hasProperty);
836 return prototype().hasProperty(arrayIndex);
844bool QJSManagedValue::hasOwnProperty(quint32 arrayIndex)
const
846 if (!d || d->isNullOrUndefined())
849 if (QV4::String *string = d->as<QV4::String>())
850 return arrayIndex < quint32(string->d()->length());
852 if (QV4::Object *obj = d->as<QV4::Object>()) {
853 if (arrayIndex == std::numeric_limits<quint32>::max()) {
854 return obj->getOwnProperty(obj->engine()->id_uintMax()->toPropertyKey())
855 != QV4::Attr_Invalid;
857 return obj->getOwnProperty(QV4::PropertyKey::fromArrayIndex(arrayIndex))
858 != QV4::Attr_Invalid;
870QJSValue QJSManagedValue::property(quint32 arrayIndex)
const
872 if (!d || d->isNullOrUndefined())
875 if (QV4::String *string = d->as<QV4::String>()) {
876 const QString qString = string->toQString();
877 if (arrayIndex < quint32(qString.size()))
878 return qString.sliced(arrayIndex, 1);
882 if (QV4::Object *obj = d->as<QV4::Object>()) {
883 if (arrayIndex == std::numeric_limits<quint32>::max())
884 return QJSValuePrivate::fromReturnedValue(obj->get(obj->engine()->id_uintMax()));
886 return QJSValuePrivate::fromReturnedValue(obj->get(arrayIndex));
889 return prototype().property(arrayIndex);
898void QJSManagedValue::setProperty(quint32 arrayIndex,
const QJSValue &value)
903 if (QV4::Object *obj = d->as<QV4::Object>()) {
904 QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
905 if (Q_UNLIKELY(v4 && v4 != obj->engine())) {
906 qWarning(
"QJSManagedValue::setProperty() failed: "
907 "Value was created in different engine.");
911 QV4::Scope scope(v4);
912 QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(v4, value));
913 obj->put(arrayIndex, v);
956QJSValue QJSManagedValue::call(
const QJSValueList &arguments)
const
958 const QV4::FunctionObject *f = functionObjectForCall(d);
962 QV4::ExecutionEngine *engine = f->engine();
964 QV4::Scope scope(engine);
965 QV4::JSCallArguments jsCallData(scope, arguments.size());
966 *jsCallData.thisObject = engine->globalObject;
968 for (
const QJSValue &arg : arguments) {
969 if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
970 qWarning(
"QJSManagedValue::call() failed: Argument was created in different engine.");
973 jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
976 return QJSValuePrivate::fromReturnedValue(f->call(jsCallData));
988QJSValue QJSManagedValue::callWithInstance(
const QJSValue &instance,
989 const QJSValueList &arguments)
const
991 const QV4::FunctionObject *f = functionObjectForCall(d);
995 QV4::ExecutionEngine *engine = f->engine();
997 if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, instance))) {
998 qWarning(
"QJSManagedValue::callWithInstance() failed: "
999 "Instance was created in different engine.");
1003 QV4::Scope scope(engine);
1004 QV4::JSCallArguments jsCallData(scope, arguments.size());
1005 *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
1007 for (
const QJSValue &arg : arguments) {
1008 if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
1009 qWarning(
"QJSManagedValue::callWithInstance() failed: "
1010 "Argument was created in different engine.");
1013 jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
1016 return QJSValuePrivate::fromReturnedValue(f->call(jsCallData));
1028QJSValue QJSManagedValue::callAsConstructor(
const QJSValueList &arguments)
const
1030 const QV4::FunctionObject *f = functionObjectForCall(d);
1034 QV4::ExecutionEngine *engine = f->engine();
1036 QV4::Scope scope(engine);
1037 QV4::JSCallArguments jsCallData(scope, arguments.size());
1039 for (
const QJSValue &arg : arguments) {
1040 if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
1041 qWarning(
"QJSManagedValue::callAsConstructor() failed: "
1042 "Argument was created in different engine.");
1045 jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
1048 return QJSValuePrivate::fromReturnedValue(f->callAsConstructor(jsCallData));
1084QStringList QJSManagedValue::jsMetaMembers()
const
1089 if (QV4::InternalClass *c = d->as<QV4::InternalClass>()) {
1090 const auto heapClass = c->d();
1091 const int size = heapClass->size;
1093 result.reserve(size);
1094 QV4::Scope scope(c->engine());
1095 for (
int i = 0; i < size; ++i) {
1096 QV4::ScopedValue key(scope, heapClass->keyAt(i));
1097 result.append(key->toQString());
1117QJSManagedValue QJSManagedValue::jsMetaInstantiate(
const QJSValueList &values)
const
1122 if (QV4::InternalClass *c = d->as<QV4::InternalClass>()) {
1123 QV4::ExecutionEngine *engine = c->engine();
1124 QJSManagedValue result(engine);
1125 *result.d = c->engine()->newObject(c->d());
1126 QV4::Object *o = result.d->as<QV4::Object>();
1128 QV4::Scope scope(engine);
1129 QV4::ScopedValue val(scope);
1130 for (uint i = 0, end = qMin(qsizetype(c->d()->size), values.size()); i < end; ++i) {
1131 const QJSValue &arg = values[i];
1132 if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
1133 qWarning(
"QJSManagedValue::instantiate() failed: "
1134 "Argument was created in different engine.");
1135 return QJSManagedValue();
1137 val = QJSValuePrivate::convertToReturnedValue(engine, arg);
1138 o->setProperty(i, val);