Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QV4::ReferenceObject Class Reference

An object that keeps track of the provenance of its owned value, allowing to reflect mutations on the original instance. More...

#include <qv4referenceobject_p.h>

Inheritance diagram for QV4::ReferenceObject:
Collaboration diagram for QV4::ReferenceObject:

Static Public Member Functions

template<typename HeapObject>
static bool readReference (HeapObject *ref)
template<typename HeapObject>
static bool writeBack (HeapObject *ref, int internalIndex=AllProperties)
template<typename HeapObject>
static HeapObject * detached (HeapObject *ref)
Static Public Member Functions inherited from QV4::Object
static ReturnedValue getValue (const Value *thisObject, const Value &v, PropertyAttributes attrs)
static ReturnedValue getValueAccessor (const Value *thisObject, const Value &v, PropertyAttributes attrs)
static ReturnedValue checkedInstanceOf (ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var)
Static Public Member Functions inherited from QV4::Managed
static QString typeToString (Type)
Static Public Member Functions inherited from QV4::Value
static constexpr Value fromStaticValue (StaticValue staticValue)
static constexpr Value undefined ()
static Value fromHeapObject (HeapBasePtr m)
static bool toBooleanImpl (Value val)
static double toNumberImpl (Value v)
static Heap::StringtoString (ExecutionEngine *e, Value val)
static Heap::Object * toObject (ExecutionEngine *e, Value val)
static constexpr Value fromReturnedValue (ReturnedValue val)
static double toInteger (double d)
static int toInt32 (double d)
static unsigned int toUInt32 (double d)
static constexpr Value emptyValue ()
static constexpr Value fromBoolean (bool b)
static constexpr Value fromInt32 (int i)
static constexpr Value undefinedValue ()
static constexpr Value nullValue ()
static Value fromDouble (double d)
static Value fromUInt32 (uint i)
Static Public Member Functions inherited from QV4::StaticValue
static int valueOffset ()
static int tagOffset ()
static constexpr quint64 tagValue (quint32 tag, quint32 value)
static constexpr quint64 tagBitMask (TagBit bit)
static bool integerCompatible (StaticValue a, StaticValue b)
static bool bothDouble (StaticValue a, StaticValue b)
static QV4_NEARLY_ALWAYS_INLINE bool isInt32 (double d)
static constexpr StaticValue fromReturnedValue (ReturnedValue val)
static constexpr StaticValue emptyValue ()
static constexpr StaticValue fromBoolean (bool b)
static constexpr StaticValue fromInt32 (int i)
static constexpr StaticValue undefinedValue ()
static constexpr StaticValue nullValue ()
static StaticValue fromDouble (double d)
static StaticValue fromUInt32 (uint i)
static double toInteger (double d)
static int toInt32 (double d)
static unsigned int toUInt32 (double d)

Static Public Attributes

static constexpr const int AllProperties = -1
Static Public Attributes inherited from QV4::StaticValue
static constexpr quint64 ExponentMask = 0b0111111111110000ull << 48
static constexpr quint64 Top1Mask = 0b1000000000000000ull << 48
static constexpr quint64 Upper3Mask = 0b0000000000001110ull << 48
static constexpr quint64 Lower5Mask = 0b0000000000011111ull
static constexpr quint64 ManagedMask = ExponentMask | quint64(TagBit::Unmanaged) << Tag_Shift
static constexpr quint64 DoubleMask = ManagedMask | quint64(TagBit::Special) << Tag_Shift
static constexpr quint64 NumberMask = ManagedMask | quint64(TagBit::Number) << Tag_Shift
static constexpr quint64 IntOrBoolMask = ManagedMask | quint64(TagBit::IntOrBool) << Tag_Shift
static constexpr quint64 IntCompatMask = ManagedMask | quint64(TagBit::IntCompat) << Tag_Shift
static constexpr quint64 EncodeMask = DoubleMask | NumberMask
static constexpr quint64 DoubleDiscriminator = ((quint64(TagBit::Unmanaged) | quint64(TagBit::Special)) << Tag_Shift)
static constexpr quint64 NumberDiscriminator = ((quint64(TagBit::Unmanaged) | quint64(TagBit::Number)) << Tag_Shift)

Additional Inherited Members

Public Types inherited from QV4::Object
enum  { NInlineProperties = 2 }
enum  { IsObject = true , GetterOffset = 0 , SetterOffset = 1 }
enum  ThrowOnFailure { DoThrowOnRejection , DoNotThrow }
Public Types inherited from QV4::Managed
enum  {
  IsExecutionContext = false , IsString = false , IsStringOrSymbol = false , IsObject = false ,
  IsTailCallable = false , IsErrorObject = false , IsArrayData = false
}
enum  { NInlineProperties = 0 }
enum  Type {
  Type_Invalid , Type_String , Type_Object , Type_Symbol ,
  Type_ArrayObject , Type_FunctionObject , Type_GeneratorObject , Type_BooleanObject ,
  Type_NumberObject , Type_StringObject , Type_SymbolObject , Type_DateObject ,
  Type_RegExpObject , Type_ErrorObject , Type_ArgumentsObject , Type_JsonObject ,
  Type_MathObject , Type_ProxyObject , Type_UrlObject , Type_UrlSearchParamsObject ,
  Type_ExecutionContext , Type_InternalClass , Type_SetIteratorObject , Type_MapIteratorObject ,
  Type_ArrayIteratorObject , Type_StringIteratorObject , Type_ForInIterator , Type_RegExp ,
  Type_V4Sequence , Type_QmlListProperty , Type_V4QObjectWrapper , Type_QMLTypeWrapper ,
  Type_V4ReferenceObject , Type_QMLValueTypeWrapper , Type_MemberData , Type_ArrayData ,
  Type_StringOrSymbol
}
Public Types inherited from QV4::Value
using ManagedPtr = Managed *
Public Types inherited from QV4::StaticValue
enum class  TagBit {
  SpecialNegative = 0b10000000000000000000 << 12 , SpecialQNaN = 0b00000000000010000000 << 12 , Special = 0b00000000000001000000 << 12 , IntCompat = 0b00000000000000100000 << 12 ,
  Unmanaged = 0b00000000000000010000 << 12 , IntOrBool = 0b00000000000000001000 << 12 , Number = 0b00000000000000000100 << 12
}
enum  Type {
  Managed_Type = 0 , Double_Type = 1 , Undefined_Type = 2 , Empty_Type = quint32(TagBit::Unmanaged) ,
  Null_Type = Empty_Type | quint32(TagBit::IntCompat) , Boolean_Type = Null_Type | quint32(TagBit::IntOrBool) , Integer_Type = Boolean_Type | quint32(TagBit::Number)
}
enum  {
  Tag_Shift = 32 , IsIntegerConvertible_Shift = 48 , IsIntegerConvertible_Value = 3 , IsIntegerOrBool_Shift = 47 ,
  IsIntegerOrBool_Value = 7
}
enum class  QuickType : quint32 {
  Managed = Managed_Type , Empty = Empty_Type , Null = Null_Type , Boolean = Boolean_Type ,
  Integer = Integer_Type , PlusInf = quint32(TagBit::Number) | quint32(TagBit::Special) | quint32(TagBit::Unmanaged) , MinusInf = PlusInf | quint32(TagBit::SpecialNegative) , NaN = PlusInf | quint32(TagBit::SpecialQNaN) ,
  MinusNaN = NaN | quint32(TagBit::SpecialNegative)
}
enum  {
  QT_Empty = Empty_Type , QT_Null = Null_Type , QT_Bool = Boolean_Type , QT_Int = Integer_Type ,
  QuickType_Shift = Tag_Shift
}
using HeapBasePtr = Heap::Base *
using ValueTypeInternal = QuickType
Public Member Functions inherited from QV4::Object
void setInternalClass (Heap::InternalClass *ic)
const ValuepropertyData (uint index) const
Heap::ArrayData * arrayData () const
void setArrayData (ArrayData *a)
void getProperty (const InternalClassEntry &entry, Property *p) const
void setProperty (const InternalClassEntry &entry, const Property *p)
void setProperty (uint index, Value v) const
void setProperty (uint index, Heap::Base *b) const
void setProperty (ExecutionEngine *engine, uint index, Value v) const
void setProperty (ExecutionEngine *engine, uint index, Heap::Base *b) const
const VTablevtable () const
PropertyAttributes getOwnProperty (PropertyKey id, Property *p=nullptr) const
PropertyIndex getValueOrSetter (PropertyKey id, PropertyAttributes *attrs)
bool hasProperty (PropertyKey id) const
bool defineOwnProperty (PropertyKey id, const Property *p, PropertyAttributes attrs)
ReturnedValue getValue (const Value &v, PropertyAttributes attrs) const
ReturnedValue getValueByIndex (uint propertyIndex) const
bool putValue (uint memberIndex, PropertyAttributes attrs, const Value &value)
void defineDefaultProperty (StringOrSymbol *name, const Value &value, PropertyAttributes attributes=Attr_Data|Attr_NotEnumerable)
void defineDefaultProperty (const QString &name, const Value &value, PropertyAttributes attributes=Attr_Data|Attr_NotEnumerable)
void defineDefaultProperty (const QString &name, VTable::Call code, int argumentCount=0, PropertyAttributes attributes=Attr_Data|Attr_NotEnumerable)
void defineDefaultProperty (StringOrSymbol *name, VTable::Call code, int argumentCount=0, PropertyAttributes attributes=Attr_Data|Attr_NotEnumerable)
void defineAccessorProperty (const QString &name, VTable::Call getter, VTable::Call setter)
void defineAccessorProperty (StringOrSymbol *name, VTable::Call getter, VTable::Call setter)
void defineReadonlyProperty (const QString &name, const Value &value)
void defineReadonlyProperty (String *name, const Value &value)
void defineReadonlyConfigurableProperty (const QString &name, const Value &value)
void defineReadonlyConfigurableProperty (StringOrSymbol *name, const Value &value)
void addSymbolSpecies ()
void insertMember (StringOrSymbol *s, const Value &v, PropertyAttributes attributes=Attr_Data)
void insertMember (StringOrSymbol *s, const Property *p, PropertyAttributes attributes)
bool isExtensible () const
bool preventExtensions ()
Heap::Object * getPrototypeOf () const
bool setPrototypeOf (const Object *p)
void setPrototypeUnchecked (const Object *p)
void copyArrayData (Object *other)
bool setArrayLength (uint newLen)
void setArrayLengthUnchecked (uint l)
void arraySet (uint index, const Property *p, PropertyAttributes attributes=Attr_Data)
void arraySet (uint index, const Value &value)
bool arrayPut (uint index, const Value &value)
bool arrayPut (uint index, const Value *values, uint n)
void setArrayAttributes (uint i, PropertyAttributes a)
void push_back (const Value &v)
ArrayData::Type arrayType () const
void setArrayType (ArrayData::Type t)
void arrayReserve (uint n)
void arrayCreate ()
void initSparseArray ()
SparseArrayNodesparseBegin () const
SparseArrayNodesparseEnd () const
bool protoHasArray ()
ReturnedValue get (StringOrSymbol *name, bool *hasProperty=nullptr, const Value *receiver=nullptr) const
ReturnedValue get (uint idx, bool *hasProperty=nullptr, const Value *receiver=nullptr) const
QT_DEPRECATED ReturnedValue getIndexed (uint idx, bool *hasProperty=nullptr) const
ReturnedValue get (PropertyKey id, const Value *receiver=nullptr, bool *hasProperty=nullptr) const
bool put (StringOrSymbol *name, const Value &v, Value *receiver=nullptr)
bool put (uint idx, const Value &v, Value *receiver=nullptr)
QT_DEPRECATED bool putIndexed (uint idx, const Value &v)
bool put (PropertyKey id, const Value &v, Value *receiver=nullptr)
bool setIndexed (uint idx, const Value &v, ThrowOnFailure shouldThrow)
bool set (StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow)
bool deleteProperty (PropertyKey id)
OwnPropertyKeyIteratorownPropertyKeys (Value *target) const
qint64 getLength () const
ReturnedValue instanceOf (const Value &var) const
bool isConcatSpreadable () const
bool isArray () const
const FunctionObjectspeciesConstructor (Scope &scope, const FunctionObject *defaultConstructor) const
bool setProtoFromNewTarget (const Value *newTarget)
ReturnedValue resolveLookupGetter (ExecutionEngine *engine, Lookup *lookup) const
bool resolveLookupSetter (ExecutionEngine *engine, Lookup *lookup, const Value &value)
int metacall (QMetaObject::Call call, int index, void **a)
Public Member Functions inherited from QV4::Managed
Heap::InternalClassinternalClass () const
const VTablevtable () const
ExecutionEngineengine () const
bool isV4SequenceType () const
bool isV4QObjectWrapper () const
bool isQmlListPropertyType () const
bool isArrayLike () const
bool isArrayObject () const
bool isStringObject () const
bool isSymbolObject () const
QString className () const
bool isEqualTo (const Managed *other) const
bool inUse () const
bool markBit () const
void mark (MarkStack *markStack)
Q_ALWAYS_INLINE Heap::BaseheapObject () const
template<typename T>
T * cast ()
template<typename T>
const T * cast () const
Public Member Functions inherited from QV4::Value
bool isString () const
bool isStringOrSymbol () const
bool isSymbol () const
bool isObject () const
bool isFunctionObject () const
QML_NEARLY_ALWAYS_INLINE StringstringValue () const
QML_NEARLY_ALWAYS_INLINE StringOrSymbolstringOrSymbolValue () const
QML_NEARLY_ALWAYS_INLINE SymbolsymbolValue () const
QML_NEARLY_ALWAYS_INLINE ObjectobjectValue () const
QML_NEARLY_ALWAYS_INLINE ManagedPtr managed () const
QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject () const
int toUInt16 () const
int toInt32 () const
unsigned int toUInt32 () const
qint64 toLength () const
qint64 toIndex () const
bool toBoolean () const
double toInteger () const
ReturnedValue convertedToNumber () const
double toNumber () const
double toNumberImpl () const
QString toQStringNoThrow () const
QString toQString () const
QString toQString (bool *ok) const
Heap::StringtoString (ExecutionEngine *e) const
QV4::PropertyKey toPropertyKey (ExecutionEngine *e) const
Heap::Object * toObject (ExecutionEngine *e) const
bool isPrimitive () const
template<typename T>
const T * as () const
template<typename T>
T * as ()
template<typename T>
T * cast ()
template<typename T>
const T * cast () const
uint asArrayLength (bool *ok) const
bool sameValue (Value other) const
bool sameValueZero (Value other) const
void mark (MarkStack *markStack)
Valueoperator= (const ScopedValue &v)
Valueoperator= (ReturnedValue v)
Valueoperator= (ManagedPtr m)
Valueoperator= (HeapBasePtr o)
template<typename T>
Valueoperator= (const Scoped< T > &t)
template<>
const ArrayObjectas () const
template<>
const FunctionObjectas () const
template<>
const StringOrSymbolas () const
template<>
const Stringas () const
template<>
const DateObjectas () const
template<>
const Managedas () const
template<>
const Objectas () const
template<>
const ErrorObjectas () const
template<>
const UrlObjectas () const
template<>
const UrlSearchParamsObjectas () const
Public Member Functions inherited from QV4::StaticValue
 StaticValue ()=default
constexpr StaticValue (quint64 val)
StaticValueoperator= (ReturnedValue v)
template<typename Value>
StaticValueoperator= (const Value &)
template<typename Value>
const ValueasValue () const
template<typename Value>
ValueasValue ()
QV4_NEARLY_ALWAYS_INLINE constexpr quint64rawValueRef ()
QV4_NEARLY_ALWAYS_INLINE constexpr quint64 rawValue () const
QV4_NEARLY_ALWAYS_INLINE constexpr void setRawValue (quint64 raw)
QV4_NEARLY_ALWAYS_INLINE constexpr void setTagValue (quint32 tag, quint32 value)
QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value () const
QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag () const
QV4_NEARLY_ALWAYS_INLINE constexpr void setTag (quint32 tag)
QV4_NEARLY_ALWAYS_INLINE constexpr int int_32 () const
QV4_NEARLY_ALWAYS_INLINE constexpr void setInt_32 (int i)
QV4_NEARLY_ALWAYS_INLINE uint uint_32 () const
QV4_NEARLY_ALWAYS_INLINE constexpr void setEmpty ()
Type type () const
quint64 quickType () const
bool isEmpty () const
bool isNull () const
bool isBoolean () const
bool isInteger () const
bool isNullOrUndefined () const
bool isUndefined () const
bool isDouble () const
bool isNumber () const
bool isManagedOrUndefined () const
bool isManaged () const
bool isIntOrBool () const
bool integerCompatible () const
bool isNaN () const
bool isPositiveInt () const
QV4_NEARLY_ALWAYS_INLINE double doubleValue () const
QV4_NEARLY_ALWAYS_INLINE void setDouble (double d)
bool isInt32 ()
double asDouble () const
bool booleanValue () const
int integerValue () const
bool tryIntegerConversion ()
bool toBoolean () const
int toInt32 () const
ReturnedValuedata_ptr ()
constexpr ReturnedValue asReturnedValue () const
template<>
StaticValueoperator= (const Value &value)
template<typename Managed>
StaticValueoperator= (const Managed &m)
template<>
ValueasValue ()
template<>
const ValueasValue () const
Public Attributes inherited from QV4::StaticValue
quint64 _val
Static Protected Member Functions inherited from QV4::Object
static ReturnedValue virtualGet (const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
static bool virtualPut (Managed *m, PropertyKey id, const Value &value, Value *receiver)
static bool virtualDeleteProperty (Managed *m, PropertyKey id)
static bool virtualHasProperty (const Managed *m, PropertyKey id)
static PropertyAttributes virtualGetOwnProperty (const Managed *m, PropertyKey id, Property *p)
static bool virtualDefineOwnProperty (Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
static bool virtualIsExtensible (const Managed *m)
static bool virtualPreventExtensions (Managed *)
static Heap::Object * virtualGetPrototypeOf (const Managed *)
static bool virtualSetPrototypeOf (Managed *, const Object *)
static OwnPropertyKeyIteratorvirtualOwnPropertyKeys (const Object *m, Value *target)
static qint64 virtualGetLength (const Managed *m)
static ReturnedValue virtualInstanceOf (const Object *typeObject, const Value &var)
static ReturnedValue virtualResolveLookupGetter (const Object *object, ExecutionEngine *engine, Lookup *lookup)
static bool virtualResolveLookupSetter (Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
static int virtualMetacall (Object *object, QMetaObject::Call call, int index, void **a)
Static Protected Member Functions inherited from QV4::Managed
static bool virtualIsEqualTo (Managed *m, Managed *other)
Static Protected Attributes inherited from QV4::VTableBase
static constexpr VTable::Destroy virtualDestroy = nullptr
static constexpr VTable::IsEqualTo virtualIsEqualTo = nullptr
static constexpr VTable::Get virtualGet = nullptr
static constexpr VTable::Put virtualPut = nullptr
static constexpr VTable::DeleteProperty virtualDeleteProperty = nullptr
static constexpr VTable::HasProperty virtualHasProperty = nullptr
static constexpr VTable::GetOwnProperty virtualGetOwnProperty = nullptr
static constexpr VTable::DefineOwnProperty virtualDefineOwnProperty = nullptr
static constexpr VTable::IsExtensible virtualIsExtensible = nullptr
static constexpr VTable::PreventExtensions virtualPreventExtensions = nullptr
static constexpr VTable::GetPrototypeOf virtualGetPrototypeOf = nullptr
static constexpr VTable::SetPrototypeOf virtualSetPrototypeOf = nullptr
static constexpr VTable::GetLength virtualGetLength = nullptr
static constexpr VTable::OwnPropertyKeys virtualOwnPropertyKeys = nullptr
static constexpr VTable::InstanceOf virtualInstanceOf = nullptr
static constexpr VTable::Call virtualCall = nullptr
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr
static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr
static constexpr VTable::CallWithMetaTypes virtualConvertAndCall = nullptr
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr
static constexpr VTable::Metacall virtualMetacall = nullptr

Detailed Description

An object that keeps track of the provenance of its owned value, allowing to reflect mutations on the original instance.

In QML, certain types are conceptually passed by value. Instances of those types are always copied when they are accessed or passed around.

Let those be "Copied Type"s.

For example, suppose that {foo} is an instance of a Copied Type that has a member {bar} that has some value {X}.

Consider the following example:

\qml import QtQuick

Item { Component.onCompleted: { foo.bar = Y console.log(foo.bar) } } \endqml

Where {Y} is some value that can inhabit {foo.bar} and whose stringified representation is distinguishable from {X}.

One might expect that a stringified representation of {Y} should be logged. Nonetheless, as {foo} is a Copied Type, accessing it creates a copy. The access to the {bar} member and its further mutation is performed on the copy that was created, and thus is not retained by the object that {foo} refers to.

If {copy} is an operation that performs a deep-copy of an object and returns it, the above snippet can be considered implicitly equivalent to the following:

\qml import QtQuick

Item { Component.onCompleted: { copy(foo).bar = Y console.log(copy(foo).bar) } } \endqml

This can generally be surprising as it stands in contrast to the effect that the above assignment would have if {foo} wasn't a Copied Type. Similarly, it stands in contrast to what one could expect from the outcome of the same assignment in a Javascript environment, where the mutation might be expected to generally be visible in later steps no matter the type of {foo}.

A ReferenceObject can be used to avoid this inconsistency by wrapping a value and providing a "write-back" mechanism that can reflect mutations back on the original value.

Furthermore, a ReferenceObject can be used to load the data from the original value to ensure that the two values remain in sync, as the value might have been mutated while the copy is still alive, conceptually allowing for an "inverted write-back".

ReferenceObject is intended to be extended by inheritance.

An object that is used to wrap a value that is copied around but has a provenance that requires a write-back, can inherit from ReferenceObject to plug into the write-back behavior.

The heap part of the object should subclass QV4::Heap::ReferenceObject while the object part should subclass QV4::ReferenceObject.

When initializing the heap part of the subclass, QV4::Heap::ReferenceObject::init should be called to set up the write-back mechanism.

The write-back mechanism stores a reference to an object and, potentially, a property index to write-back at.

Furthermore, a series of flags can be used to condition the behavior of the write-back.

For example:

void QV4::Heap::Foo::init(Heap::Object *object) {
ReferenceObject::init(object, 1, ReferenceObject::Flag::CanWriteBack);
// Some further initialization code
...
}

The snippet is an example of some sub-class {Foo} of ReferenceObject setting up for a write-back to the property at index 1 of some object {object}.

Generally, a sub-class of ReferenceObject will be used to wrap one or more Copied Types and provide a certain behavior.

In certain situations there is no need to setup a write-back. For example, we might have certain cases where there is no original value to be wrapped while still in need of providing an object of the sub-classing type.

One example of such a behavior is that of returning an instance from a C++ method to QML.

When that is the case, the following initialization can be provided:

void QV4::Heap::Foo::init(Heap::Object *object) {
ReferenceObject::init(nullptr, -1, NoFlag);
// Some further initialization code
...
}

In certain cases, we try to avoid read-backs when we know that we have the latest data available already, see \l{Limiting reads on a QObject property}.

Certain implementation of ReferenceObject, might want to lazily load the data on the first read, rather than on the initialization of the reference. One such example would be QQmlValueTypeWrapper.

When that is the case, the IsDirty flag should be passed at initialiazation time. For example:

void QV4::Heap::Foo::init(Heap::Object *object) {
ReferenceObject::init(object, 1, ReferenceObject::Flag::CanWriteBack | ReferenceObject::Flag::IsDirty);
// Some further initialization code
...
}

If the flag is not passed there the first read might be elided, leaving the object in an incorrect state.

Generally, to use the base implementation of write and read backs, as provided by QV4::ReferenceObject::readReference and QV4::ReferenceObject::writeBack, a sub-class should provide the following interface:

void *storagePointer();
const void *storagePointer();
bool setVariant(const QVariant &variant);
\inmodule QtCore
Definition qvariant.h:66
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior, V4ObjectSet *visitedObjects)

The two overloads of {storagePointer} should provide access to the internal backing storage of the ReferenceObject.

Generally, a ReferenceObject will be wrapping some instance of a C++ type, owning a copy of the original instance used as a storage for writes and reads. An implementation of {storagePointer} should give access to this backing storage, which is used to know what value to write-back and where to write when reading back from the original value.

For example, a Sequence type that wraps a QVariantList will own its own instance of a QVariantList. The implementation for {storagePointer} should give access to that owned instance.

{toVariant} should provide a QVariant wrapped representation of the internal storage that the ReferenceObject uses. This is used during the write-back of a ReferenceObject whose original value was a QVariant backed instance.

Do remember that instances of a ReferenceObject that are backing QVariant values should further pass the QV4::Heap::ReferenceObject::Flag::IsVariant flag at initialization time.

On the opposite side, {setVariant} should switch the value that the ReferenceObject stores with the provided variant. This is used when a QVariant backed ReferenceObject performs a read of its original value, to allow for synchronization.

It is still possible to use ReferenceObject without necessarily providing the above interface. QV4::DateObject is an example of a ReferenceObject sub-class that provides its own writeBack implementation and doesn't abide by the above.

With a sub-class of ReferenceObject that was set-up as above, a write-back can be performed by calling QV4::ReferenceObject::writeBack.

For example, some ReferenceObject subclass {Foo} might be backing, say, some map-like object.

Internally, insertion of an element might pass by some method, say {insertElement}. An implementation might, for example, look like the following:

bool Foo::insertElement(const QString& key, const Value& value) {
// Insert the element if possible
...
...
// Some further handling
}
EGLOutputLayerEXT EGLint EGLAttrib value
[3]
GLuint64 key
static bool writeBack(HeapObject *ref, int internalIndex=AllProperties)

The call to writeBack will ensure that the newly inserted element will be reflected on the original value where the object originates from.

Here {d()}, with {Foo} being a sub-class of ReferenceObject and thus of Object, is the heap part of {Foo} that should provide the interface specificed above and owns the actual storage of the stored value.

QV4::ReferenceObject::readReference provides a way to obtain the current state of the value that the ReferenceObject refers to.

When this read is performed, the obtained value will be stored back into the backing storage for the ReferenceObject.

This allows the ReferenceObject to lazily load the latest data on demand and correctly reflect the original value.

For example, say that {Foo} is a sub-class of ReferenceObject that is used to back array-like values.

{Foo} should provide the usual {virtualGetLength} method to support the {length} property that we expect an array to have.

In a possible implementation of {virtualGetLength}, {Foo} should ensure that readReference is called before providing a value for the length, to ensure that the latest data is available.

For example:

qint64 Foo::virtualGetLength(const Managed *m)
{
const Foo *foo = static_cast<const Foo *>(m);
foo->readReference(d());
// Return the length from the owned storage
}
const GLfloat * m
[1]
long long qint64
Definition qtypes.h:65
QString foo
[14]

In most cases we cannot know whether the original data was modified between read accesses. This generally forces a read to be performed each time we require the latest data, even if we might have it already.

This can have surprising results, as certain procedure might require reading the data multiple times to be performed, which sometimes can be very expensive.

When the original data comes from the property of a {QObject}, and the property has a \tt{NOTIFY} signal or is \tt{BINDABLE}, we can subscribe to the signal to know when the data is actually modified outside our control, so that we need to fetch it again.

A ReferenceObject can take advantage of this to reduce the number of reads that are required when dealing with a {QObject}'s property provening data.

When a property has a \tt{NOTIFY} signal and is a \tt{BINDABLE} at the same time, we only need to use one such connection. Currently, the \tt{BINDABLE} subscription will take predecedence.

ReferenceObjects that are part of a \l{Reference object chains}{chain}, will traverse the chain up until a QOjbect holding root is found, and connect based on that object. As read/write backs in a chain are always propagated up the chain, this allow ReferenceObjects that are not directly parented to relevant element to still avoid unnecesary reads.

For example, the property of a value type exposed by a Q_GADGET, cannot have a \tt{NOTIFY} signal. Nonetheless, if a change were to occur to the parent value type or the property itself, that change would be propagated up the chain, possibly triggering a \tt{NOTIFY} signal that is part of the chain. Thus, by connecting to that upper \tt{NOTIFY} signal, we can still reliably know if a change was performed on the property itself and thus avoid reduce the number of reads.

As changes in the chain that do not really invalidate the data of that property will still trigger that same \tt{NOTIFY} signal, sometimes we will perform a read that is unnecessary due to granularity at which we are working. This is the case, returning to the example above, when a different property of that same value type will be changed.

This should still be a win, as we still expect to cut off multiple reads that would be performed without the optimization.

The default implementation for QV4::ReferenceObject::readReference will take care of performing this optimization already.

Derived objects that provide their own readReference implementation can plug into QV4::Heap::ReferenceObject::isDirty, QV4::Heap::ReferenceObject::setDirty and QV4::Heap::ReferenceObject::isConnected to provide the same optimization.

A ReferenceObject uses a "dirty" flag to track whether the data should be read again. If the ReferenceObject refers to a {QObject}'s property that has a \tt{NOTIFY} signal or is \tt{BINDABLE}, it will set the flag each time the \tt{NOTIFY} signal is emitted or the \tt{BINDABLE} is changed.

isDirty returns whether the flag is set and, thus, a readReference implementation should avoid performing the read itself when the method returns true.

After a read is performed, the "dirty" flag should be set again if the read was unsuccessful. The flag can be modified by usages of setDirty.

Generally, this only applies to instances of ReferenceObject that provene from a {QObject}'s property that has a notify signal, as that is the case that allows us to know when a read is required.

In all other cases, a ReferenceObject should always be "dirty" and perform a read, as it cannot know if the data was modified since its last read. This case will initially be managed by the base constructor for ReferenceObject, nonetheless derived objects with a custom readReference implementation need to take it into accoutn when setting the "dirty" flag after a read.

isConnected can be used to discern between the two cases, as it will only return true when the ReferenceObject is connected to a NOTIFY signal that can modify the "dirty" flag. When isConnected is false, a read implementation should always keep the ReferenceObject in a permanent "dirty" state, to ensure that the correct data is fetched when required.

Note
We generally consider location-aware write-backs to be a mistake and expect to generally avoid further uses of them. Due to backward compatibility promises they cannot be universally enforced, possibly creating discrepancies in certain behaviors. If at some point possible, the feature might be backtracked on and removed, albeit this has shown to be difficult due to certain existing cross-dependencies.

Consider the following code:

\qml import QtQuick

Text { Component.onCompleted: { var f = font // font is a value type and f is a value type reference f.bold = true; otherText.font = f } } \endqml

Remembering that {font} is a Copied Type in QtQuick, {f} will be a Copied Type reference, internally backed by a ReferenceObject. Changing the {bold} property of {f} would internally perform a write-back which will reflect on the original {font} property of the {Text} component, as we would expect from the definition we gave above.

Nonetheless, we could generally expect that the intention behind the code wasn't to update the original {font} property, but to pass a slightly modified version of its value to {otherText}.

To avoid introducing this kind of possibly unintended behavior while still supporting a solution to the original problem, ReferenceObject allows limiting the availability of write-backs to a specific source location.

For example, by limiting the availability of write-backs to the single statement where a Copied Type reference is created, we can address the most common cases of the original issue while avoiding the unintuitive behavior of the above.

To enable source location enforcement, QV4::Heap::ReferenceObject::Flag::EnforcesLocation should be set when the ReferenceObject is initialized.

A reference location should be set by calling QV4::Heap::ReferenceObject::setLocation. For example, during initialization, one might be set to limit write-backs to the currently processed statement, where the ReferenceObject was created, as follows:

void Heap::Sequence::Foo::init(..., Heap::ReferenceObject::Flags flags) {
...
ReferenceObject::init(..., flags & ReferenceObject::Flag::EnforcesLocation);
...
if (CppStackFrame *frame = internalClass->engine->currentStackFrame)
setLocation(frame->v4Function, frame->statementNumber());
...
}
GLbitfield flags
QFrame frame
[0]
Heap::InternalClass * internalClass() const

Do note that calls to QV4::ReferenceObject::writeBack and QV4::ReferenceObject::readReference do not directly take into account location enforcement.

This should generally be handled by the sub-class. QV4::Heap::ReferenceObject::isAttachedToProperty can be used to recognize whether the reference is still suitable for write-backs in a location-enforcement-aware way.

ReferenceObject can be nested.

For example, consider:

a.b.c
GLboolean GLboolean GLboolean GLboolean a

Where {a} is some object exposed to QML, {b} is a property of {a} and {c} is a property of {b}.

Based on what each of {a}, {b} and {c} is, multiple ReferenceObject instances, parented to one another, might be introduced.

For example, if {a} is a Q_OBJECT, {b} is a value type and {c} is a type that will be converted to a QV4::Sequence, {a} will be wrapped by a QObjectWrapper, {b} will be wrapped by a QQmlValueTypeWrapper which is parented to the QObjectWrapper wrapping {a} and {c} will be a Sequence that is parented to the QQmlValueTypeWrapper wrapping {b}.

This parenting chain is used to enable recursive read/write backs, ensuring that a read/write back travels up the chain as required so that the latest data is available on every relevant element.

At certain points in the chain, it is possible that a non-reference object is introduced.

For example, this is always the case when a Q_OBJECT is retrieved, as it will be wrapped in a QObjectWrapper which is not a reference object.

This breaks the chain of parenting and introduces the start of a new chain. As a QObjectWrapper directly stores a pointer to the original object, it doesn't need to perform the same read/write backs that reference objects do. Similarly, child reference objects only need to read up to the innermost QObjectWrapper in a chain to obtain the latest data.

Returning to the example above, if {b} is a Q_OBJECT instead of a value type, then it will be the root of the reference chain that has {c} has its child, without the need to be related to the QObjectWrapper that has been built by accessing {a}.

QQmlTypeWrapper, that can wrap a QObject pointer that represents a singleton or an attached property, behaves as chain root in the exact same way that QObjectWrapper does.

Definition at line 262 of file qv4referenceobject_p.h.

Member Function Documentation

◆ detached()

template<typename HeapObject>
HeapObject * QV4::ReferenceObject::detached ( HeapObject * ref)
inlinestatic

Definition at line 320 of file qv4referenceobject_p.h.

◆ readReference()

template<typename HeapObject>
bool QV4::ReferenceObject::readReference ( HeapObject * ref)
inlinestatic

Definition at line 272 of file qv4referenceobject_p.h.

◆ writeBack()

template<typename HeapObject>
bool QV4::ReferenceObject::writeBack ( HeapObject * ref,
int internalIndex = AllProperties )
inlinestatic

Definition at line 299 of file qv4referenceobject_p.h.

Member Data Documentation

◆ AllProperties

const int QV4::ReferenceObject::AllProperties = -1
staticconstexpr

Definition at line 269 of file qv4referenceobject_p.h.


The documentation for this class was generated from the following file: