Merge remote-tracking branch 'origin/5.5' into 5.6
authorUlf Hermann <ulf.hermann@theqtcompany.com>
Tue, 18 Aug 2015 08:29:10 +0000 (10:29 +0200)
committerUlf Hermann <ulf.hermann@theqtcompany.com>
Tue, 18 Aug 2015 08:29:47 +0000 (10:29 +0200)
Conflicts:
src/qml/debugger/qv4debugservice.cpp
src/qml/jsruntime/qv4value_inl_p.h
src/qml/jsruntime/qv4value_p.h
src/qml/memory/qv4mm.cpp
src/qml/memory/qv4mm_p.h
src/qml/qml/qqmlnotifier_p.h
src/qml/qml/qqmlproperty.cpp
src/quick/items/qquickflickable.cpp
src/quick/items/qquicktextedit.cpp
tests/auto/quick/qquickwindow/BLACKLIST

The extra changes in qqmlbinding.cpp are ported from changes to
qqmlproperty.cpp that occurred in parallel with writeBinding() being
moved to qqmlbinding.cpp.

Change-Id: I16d1920abf448c29a01822256f52153651a56356

60 files changed:
1  2 
src/particles/qquickimageparticle.cpp
src/qml/compiler/qqmltypecompiler.cpp
src/qml/compiler/qv4ssa.cpp
src/qml/jsruntime/qv4arraybuffer.cpp
src/qml/jsruntime/qv4engine.cpp
src/qml/jsruntime/qv4function.cpp
src/qml/jsruntime/qv4numberobject.cpp
src/qml/jsruntime/qv4qobjectwrapper.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4serialize.cpp
src/qml/jsruntime/qv4string.cpp
src/qml/jsruntime/qv4string_p.h
src/qml/jsruntime/qv4typedarray.cpp
src/qml/jsruntime/qv4value_p.h
src/qml/jsruntime/qv4vme_moth.cpp
src/qml/memory/qv4mm.cpp
src/qml/memory/qv4mm_p.h
src/qml/qml/qqmlbinding.cpp
src/qml/qml/qqmlcontext.cpp
src/qml/qml/qqmlengine.cpp
src/qml/qml/qqmlimport.cpp
src/qml/qml/qqmlmetatype.cpp
src/qml/qml/qqmlnotifier_p.h
src/qml/qml/qqmlproperty.cpp
src/qml/qml/qqmlpropertycache.cpp
src/qml/qml/qqmlvaluetype.cpp
src/qml/qml/qqmlvmemetaobject.cpp
src/qml/qml/qqmlvmemetaobject_p.h
src/quick/items/context2d/qquickcanvasitem.cpp
src/quick/items/qquickflickable.cpp
src/quick/items/qquickframebufferobject.cpp
src/quick/items/qquickgridview.cpp
src/quick/items/qquickimage_p.h
src/quick/items/qquickitem.cpp
src/quick/items/qquickitemview_p_p.h
src/quick/items/qquicklistview.cpp
src/quick/items/qquickrendercontrol.cpp
src/quick/items/qquicktext.cpp
src/quick/items/qquicktext_p_p.h
src/quick/items/qquicktextcontrol.cpp
src/quick/items/qquicktextedit.cpp
src/quick/items/qquicktextinput.cpp
src/quick/items/qquicktextnodeengine.cpp
src/quick/items/qquickwindow.cpp
src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
src/quick/scenegraph/qsgrenderloop.cpp
src/quick/scenegraph/qsgthreadedrenderloop.cpp
src/quick/util/qquickanimatorjob.cpp
src/quick/util/qquickanimatorjob_p.h
src/quick/util/qquickprofiler_p.h
src/quick/util/qquickstyledtext.cpp
src/quickwidgets/qquickwidget_p.h
tests/auto/qml/qml.pro
tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
tools/qmlprofiler/qmlprofilerclient.cpp
tools/qmlprofiler/qmlprofilerdata.cpp

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 096fe9fb4ce32ae12cfbe2eb70091e8b093ca54e,4a1a94e872cf0b8aaf774c6538074ed1ef3b5bc9..4ae30a7f35296fe82f84d285ad768989a7aea083
@@@ -76,19 -75,15 +76,15 @@@ void NumberPrototype::init(ExecutionEng
      ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
      ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
  
- #ifdef __INTEL_COMPILER
- # pragma warning( push )
- # pragma warning(disable: 239)
- #endif
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_INTEL(239)
      ctor->defineReadonlyProperty(QStringLiteral("MIN_VALUE"), Primitive::fromDouble(5e-324));
- #ifdef __INTEL_COMPILER
- # pragma warning( pop )
- #endif
+ QT_WARNING_POP
  
      defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
 -    defineDefaultProperty(engine->id_toString, method_toString);
 +    defineDefaultProperty(engine->id_toString(), method_toString);
      defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
 -    defineDefaultProperty(engine->id_valueOf, method_valueOf);
 +    defineDefaultProperty(engine->id_valueOf(), method_valueOf);
      defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1);
      defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential);
      defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index c0420a38dbe55029adcdda112ba05aeab46e9fc0,628950784ada49c1abe17c224569132ffc1df825..6305e6dfbbe42f39f5c8e2cf4b0341bdcf97a75e
  
  #include <QtCore/QString>
  #include "qv4global_p.h"
 +#include <private/qv4heap_p.h>
  
+ /* We cannot rely on QT_POINTER_SIZE to be set correctly on host builds. In qmldevtools the Value objects
+    are only used to store primitives, never object pointers. So we can use the 64-bit encoding. */
+ #ifdef V4_BOOTSTRAP
+ #define QV4_USE_64_BIT_VALUE_ENCODING
+ #elif QT_POINTER_SIZE == 8
+ #define QV4_USE_64_BIT_VALUE_ENCODING
+ #endif
  QT_BEGIN_NAMESPACE
  
  namespace QV4 {
@@@ -73,40 -124,32 +81,40 @@@ struct Q_QML_PRIVATE_EXPORT Valu
          Bit 15-17 is then used to encode other immediates.
      */
  
 +    quint64 _val;
 +
 +    Q_ALWAYS_INLINE quint64 val() const { return _val; }
 +    Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; }
 +    Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); }
 +    Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); }
  
 -    union {
 -        quint64 val;
 -#ifdef QV4_USE_64_BIT_VALUE_ENCODING
 -        Heap::Base *m;
 -#else
 -        double dbl;
 -#endif
 -        struct {
 -#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
 -            uint tag;
 -#endif
 -            union {
 -                uint uint_32;
 -                int int_32;
 -#ifndef QV4_USE_64_BIT_VALUE_ENCODING
 -                Heap::Base *m;
 -#endif
 -            };
  #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
 -            uint tag;
 +    static inline int valueOffset() { return 0; }
 +    static inline int tagOffset() { return 4; }
 +    Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
 +    Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
 +    Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
 +#else // !Q_LITTLE_ENDIAN
 +    static inline int valueOffset() { return 4; }
 +    static inline int tagOffset() { return 0; }
 +    Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; }
 +    Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); }
 +    Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; }
  #endif
 -        };
 -    };
 +
- #if QT_POINTER_SIZE == 8
++#ifdef QV4_USE_64_BIT_VALUE_ENCODING
 +    Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; }
 +    Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); }
- #else // QT_POINTER_SIZE == 4
++#else // !QV4_USE_64_BIT_VALUE_ENCODING
 +    Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; }
 +    Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); }
 +#endif
 +
 +    Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; }
 +    Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); }
 +    Q_ALWAYS_INLINE uint uint_32() const { return value(); }
  
- #if QT_POINTER_SIZE == 4
+ #ifndef QV4_USE_64_BIT_VALUE_ENCODING
      enum Masks {
          SilentNaNBit           =                  0x00040000,
          NaN_Mask               =                  0x7ff80000,
      }
  
      // used internally in property
 -    inline bool isEmpty() const { return tag == Empty_Type; }
 +    inline bool isEmpty() const { return tag() == Empty_Type; }
  
 -    inline bool isUndefined() const { return tag == Undefined_Type; }
 -    inline bool isNull() const { return tag == _Null_Type; }
 -    inline bool isBoolean() const { return tag == _Boolean_Type; }
 +    inline bool isUndefined() const { return tag() == Undefined_Type; }
 +    inline bool isNull() const { return tag() == _Null_Type; }
 +    inline bool isBoolean() const { return tag ()== _Boolean_Type; }
- #if QT_POINTER_SIZE == 8
+ #ifdef QV4_USE_64_BIT_VALUE_ENCODING
 -    inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; }
 -    inline bool isDouble() const { return (val >> IsDouble_Shift); }
 -    inline bool isNumber() const { return (val >> IsNumber_Shift); }
 -    inline bool isManaged() const { return !(val >> IsManaged_Shift); }
 -    inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; }
 -    inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; }
 +    inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; }
 +    inline bool isDouble() const { return (_val >> IsDouble_Shift); }
 +    inline bool isNumber() const { return (_val >> IsNumber_Shift); }
 +    inline bool isManaged() const { return !(_val >> IsManaged_Shift); }
 +    inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; }
 +    inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; }
      static inline bool integerCompatible(Value a, Value b) {
          return a.integerCompatible() && b.integerCompatible();
      }
      static inline bool bothDouble(Value a, Value b) {
          return a.isDouble() && b.isDouble();
      }
 -    double doubleValue() const {
 -        Q_ASSERT(isDouble());
 -        union {
 -            quint64 i;
 -            double d;
 -        } v;
 -        v.i = val ^ NaNEncodeMask;
 -        return v.d;
 -    }
 -    void setDouble(double d) {
 -        union {
 -            quint64 i;
 -            double d;
 -        } v;
 -        v.d = d;
 -        val = v.i ^ NaNEncodeMask;
 -        Q_ASSERT(isDouble());
 -    }
 -    inline bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; }
 +    inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; }
  #else
 -    inline bool isInteger() const { return tag == _Integer_Type; }
 -    inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
 -    inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
 -    inline bool isManaged() const { return tag == Managed_Type; }
 -    inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; }
 -    inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; }
 +    inline bool isInteger() const { return tag() == _Integer_Type; }
 +    inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
 +    inline bool isNumber() const { return tag() == _Integer_Type || (tag() & NotDouble_Mask) != NotDouble_Mask; }
 +    inline bool isManaged() const { return tag() == Managed_Type; }
 +    inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; }
 +    inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; }
      static inline bool integerCompatible(Value a, Value b) {
 -        return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
 +        return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt;
      }
      static inline bool bothDouble(Value a, Value b) {
 -        return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
 +        return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
      }
 -    double doubleValue() const { Q_ASSERT(isDouble()); return dbl; }
 -    void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); }
 -    inline bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
 +    inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
  #endif
- #if QT_POINTER_SIZE == 8
 +    Q_ALWAYS_INLINE double doubleValue() const {
 +        Q_ASSERT(isDouble());
 +        double d;
 +        quint64 v = _val;
- #if QT_POINTER_SIZE == 8
++#ifdef QV4_USE_64_BIT_VALUE_ENCODING
 +        v ^= NaNEncodeMask;
 +#endif
 +        memcpy(&d, &v, 8);
 +        return d;
 +    }
 +    Q_ALWAYS_INLINE void setDouble(double d) {
 +        memcpy(&_val, &d, 8);
++#ifdef QV4_USE_64_BIT_VALUE_ENCODING
 +        _val ^= NaNEncodeMask;
 +#endif
 +        Q_ASSERT(isDouble());
 +    }
      inline bool isString() const;
      inline bool isObject() const;
      inline bool isInt32() {
      static inline Value fromHeapObject(Heap::Base *m)
      {
          Value v;
 -        v.m = m;
 +        v.setRawValue(0);
 +        v.setM(m);
- #if QT_POINTER_SIZE == 4
+ #ifndef QV4_USE_64_BIT_VALUE_ENCODING
 -        v.tag = Managed_Type;
 +        v.setTag(Managed_Type);
  #endif
          return v;
      }
          return *this;
      }
      Value &operator=(Heap::Base *o) {
 -        m = o;
 +        setM(o);
- #if QT_POINTER_SIZE == 4
+ #ifndef QV4_USE_64_BIT_VALUE_ENCODING
 -        tag = Managed_Type;
 +        setTag(Managed_Type);
  #endif
          return *this;
      }
      }
  };
  
 -inline Managed *Value::asManaged() const
 +inline bool Value::isString() const
 +{
 +    if (!isManaged())
 +        return false;
 +    return m() && m()->vtable()->isString;
 +}
 +inline bool Value::isObject() const
 +{
 +    if (!isManaged())
 +        return false;
 +    return m() && m()->vtable()->isObject;
 +}
 +
 +inline bool Value::isPrimitive() const
 +{
 +    return !isObject();
 +}
 +
 +inline double Value::toNumber() const
 +{
 +    if (isInteger())
 +        return int_32();
 +    if (isDouble())
 +        return doubleValue();
 +    return toNumberImpl();
 +}
 +
 +
 +#ifndef V4_BOOTSTRAP
 +inline uint Value::asArrayIndex() const
  {
- #if QT_POINTER_SIZE == 8
 -    if (isManaged())
 -        return managed();
 -    return 0;
++#ifdef QV4_USE_64_BIT_VALUE_ENCODING
 +    if (!isNumber())
 +        return UINT_MAX;
 +    if (isInteger())
 +        return int_32() >= 0 ? (uint)int_32() : UINT_MAX;
 +#else
 +    if (isInteger() && int_32() >= 0)
 +        return (uint)int_32();
 +    if (!isDouble())
 +        return UINT_MAX;
 +#endif
 +    double d = doubleValue();
 +    uint idx = (uint)d;
 +    if (idx != d)
 +        return UINT_MAX;
 +    return idx;
  }
 +#endif
 +
 +inline
 +ReturnedValue Heap::Base::asReturnedValue() const
 +{
 +    return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue();
 +}
 +
 +
  
  struct Q_QML_PRIVATE_EXPORT Primitive : public Value
  {
  inline Primitive Primitive::undefinedValue()
  {
      Primitive v;
- #if QT_POINTER_SIZE == 8
+ #ifdef QV4_USE_64_BIT_VALUE_ENCODING
 -    v.val = quint64(Undefined_Type) << Tag_Shift;
 +    v.setRawValue(quint64(Undefined_Type) << Tag_Shift);
  #else
 -    v.tag = Undefined_Type;
 -    v.int_32 = 0;
 +    v.setRawValue(0);
 +    v.setTag(Undefined_Type);
 +    v.setValue(0);
  #endif
      return v;
  }
@@@ -478,50 -453,34 +486,50 @@@ inline Primitive Primitive::emptyValue(
      return v;
  }
  
 -template <typename T>
 -struct TypedValue : public Value
 +inline Primitive Primitive::nullValue()
  {
 -    template<typename X>
 -    TypedValue &operator =(X *x) {
 -        m = x;
 +    Primitive v;
- #if QT_POINTER_SIZE == 8
+ #ifndef QV4_USE_64_BIT_VALUE_ENCODING
 -        tag = Managed_Type;
 +    v.setRawValue(quint64(_Null_Type) << Tag_Shift);
 +#else
 +    v.setTagValue(_Null_Type, 0);
  #endif
 -        return *this;
 -    }
 -    TypedValue &operator =(T *t);
 -    TypedValue &operator =(const Scoped<T> &v);
 -//    TypedValue &operator =(const ManagedRef<T> &v);
 -
 -    TypedValue &operator =(const TypedValue<T> &t);
 +    return v;
 +}
  
 -    bool operator!() const { return !managed(); }
 +inline Primitive Primitive::fromBoolean(bool b)
 +{
 +    Primitive v;
 +    v.setTagValue(_Boolean_Type, b);
 +    return v;
 +}
  
 -    operator T *() { return static_cast<T *>(managed()); }
 -    T *operator->() { return static_cast<T *>(managed()); }
 -    const T *operator->() const { return static_cast<T *>(managed()); }
 -    T *getPointer() const { return static_cast<T *>(managed()); }
 +inline Primitive Primitive::fromDouble(double d)
 +{
 +    Primitive v;
 +    v.setDouble(d);
 +    return v;
 +}
  
 -    void mark(ExecutionEngine *e) { if (managed()) managed()->mark(e); }
 -};
 -typedef TypedValue<String> StringValue;
 +inline Primitive Primitive::fromInt32(int i)
 +{
 +    Primitive v;
 +    v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
 +    v.setInt_32(i);
 +    return v;
 +}
  
 +inline Primitive Primitive::fromUInt32(uint i)
 +{
 +    Primitive v;
 +    if (i < INT_MAX) {
 +        v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
 +        v.setInt_32((int)i);
 +    } else {
 +        v.setDouble(i);
 +    }
 +    return v;
 +}
  
  struct Encode {
      static ReturnedValue undefined() {
Simple merge
index 03e78df91a34e5a867b4774000a21cfcb16f9217,0000000000000000000000000000000000000000..38b4e1eaf16be6181533ae64001f85693d8ae094
mode 100644,000000..100644
--- /dev/null
@@@ -1,603 -1,0 +1,637 @@@
- bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine)
 +/****************************************************************************
 +**
 +** Copyright (C) 2015 The Qt Company Ltd.
 +** Contact: http://www.qt.io/licensing/
 +**
 +** This file is part of the QtQml module of the Qt Toolkit.
 +**
 +** $QT_BEGIN_LICENSE:LGPL21$
 +** Commercial License Usage
 +** Licensees holding valid commercial Qt licenses may use this file in
 +** accordance with the commercial license agreement provided with the
 +** Software or, alternatively, in accordance with the terms contained in
 +** a written agreement between you and The Qt Company. For licensing terms
 +** and conditions see http://www.qt.io/terms-conditions. For further
 +** information use the contact form at http://www.qt.io/contact-us.
 +**
 +** GNU Lesser General Public License Usage
 +** Alternatively, this file may be used under the terms of the GNU Lesser
 +** General Public License version 2.1 or version 3 as published by the Free
 +** Software Foundation and appearing in the file LICENSE.LGPLv21 and
 +** LICENSE.LGPLv3 included in the packaging of this file. Please review the
 +** following information to ensure the GNU Lesser General Public License
 +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
 +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 +**
 +** As a special exception, The Qt Company gives you certain additional
 +** rights. These rights are described in The Qt Company LGPL Exception
 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 +**
 +** $QT_END_LICENSE$
 +**
 +****************************************************************************/
 +
 +#include "qv4engine_p.h"
 +#include "qv4object_p.h"
 +#include "qv4objectproto_p.h"
 +#include "qv4mm_p.h"
 +#include "qv4qobjectwrapper_p.h"
 +#include <qqmlengine.h>
 +#include "PageAllocation.h"
 +#include "StdLibExtras.h"
 +
 +#include <QTime>
 +#include <QVector>
 +#include <QVector>
 +#include <QMap>
 +
 +#include <iostream>
 +#include <cstdlib>
 +#include <algorithm>
 +#include "qv4alloca_p.h"
 +#include "qv4profiling_p.h"
 +
 +#ifdef V4_USE_VALGRIND
 +#include <valgrind/valgrind.h>
 +#include <valgrind/memcheck.h>
 +#endif
 +
 +#if OS(QNX)
 +#include <sys/storage.h>   // __tls()
 +#endif
 +
 +#if USE(PTHREADS) && HAVE(PTHREAD_NP_H)
 +#include <pthread_np.h>
 +#endif
 +
 +using namespace WTF;
 +
 +QT_BEGIN_NAMESPACE
 +
 +using namespace QV4;
 +
 +struct MemoryManager::Data
 +{
 +    struct ChunkHeader {
 +        Heap::Base freeItems;
 +        ChunkHeader *nextNonFull;
 +        char *itemStart;
 +        char *itemEnd;
 +        int itemSize;
 +    };
 +
 +    bool gcBlocked;
 +    bool aggressiveGC;
 +    bool gcStats;
 +    ExecutionEngine *engine;
 +
 +    enum { MaxItemSize = 512 };
 +    ChunkHeader *nonFullChunks[MaxItemSize/16];
 +    uint nChunks[MaxItemSize/16];
 +    uint availableItems[MaxItemSize/16];
 +    uint allocCount[MaxItemSize/16];
 +    int totalItems;
 +    int totalAlloc;
 +    uint maxShift;
 +    std::size_t maxChunkSize;
 +    QVector<PageAllocation> heapChunks;
++    std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
++    std::size_t unmanagedHeapSizeGCLimit;
 +
 +    struct LargeItem {
 +        LargeItem *next;
 +        size_t size;
 +        void *data;
 +
 +        Heap::Base *heapObject() {
 +            return reinterpret_cast<Heap::Base *>(&data);
 +        }
 +    };
 +
 +    LargeItem *largeItems;
 +    std::size_t totalLargeItemsAllocated;
 +
 +    // statistics:
 +#ifdef DETAILED_MM_STATS
 +    QVector<unsigned> allocSizeCounters;
 +#endif // DETAILED_MM_STATS
 +
 +    Data()
 +        : gcBlocked(false)
 +        , engine(0)
 +        , totalItems(0)
 +        , totalAlloc(0)
 +        , maxShift(6)
 +        , maxChunkSize(32*1024)
++        , unmanagedHeapSize(0)
++        , unmanagedHeapSizeGCLimit(64 * 1024)
 +        , largeItems(0)
 +        , totalLargeItemsAllocated(0)
 +    {
 +        memset(nonFullChunks, 0, sizeof(nonFullChunks));
 +        memset(nChunks, 0, sizeof(nChunks));
 +        memset(availableItems, 0, sizeof(availableItems));
 +        memset(allocCount, 0, sizeof(allocCount));
 +        aggressiveGC = !qgetenv("QV4_MM_AGGRESSIVE_GC").isEmpty();
 +        gcStats = !qgetenv("QV4_MM_STATS").isEmpty();
 +
 +        QByteArray overrideMaxShift = qgetenv("QV4_MM_MAXBLOCK_SHIFT");
 +        bool ok;
 +        uint override = overrideMaxShift.toUInt(&ok);
 +        if (ok && override <= 11 && override > 0)
 +            maxShift = override;
 +
 +        QByteArray maxChunkString = qgetenv("QV4_MM_MAX_CHUNK_SIZE");
 +        std::size_t tmpMaxChunkSize = maxChunkString.toUInt(&ok);
 +        if (ok)
 +            maxChunkSize = tmpMaxChunkSize;
 +    }
 +
 +    ~Data()
 +    {
 +        for (QVector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
 +            Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage);
 +            i->deallocate();
 +        }
 +    }
 +};
 +
 +namespace {
 +
- //        qDebug("chunk @ %p, size = %lu, in use: %s, mark bit: %s",
- //               item, m->size, (m->inUse ? "yes" : "no"), (m->markBit ? "true" : "false"));
++bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine, std::size_t *unmanagedHeapSize)
 +{
++    Q_ASSERT(unmanagedHeapSize);
++
 +    bool isEmpty = true;
 +    Heap::Base *tail = &header->freeItems;
 +//    qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4);
 +#ifdef V4_USE_VALGRIND
 +    VALGRIND_DISABLE_ERROR_REPORTING;
 +#endif
 +    for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
 +        Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
- Heap::Base *MemoryManager::allocData(std::size_t size)
++//        qDebug("chunk @ %p, in use: %s, mark bit: %s",
++//               item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
 +
 +        Q_ASSERT((qintptr) item % 16 == 0);
 +
 +        if (m->isMarked()) {
 +            Q_ASSERT(m->inUse());
 +            m->clearMarkBit();
 +            isEmpty = false;
 +            ++(*itemsInUse);
 +        } else {
 +            if (m->inUse()) {
 +//                qDebug() << "-- collecting it." << m << tail << m->nextFree();
 +#ifdef V4_USE_VALGRIND
 +                VALGRIND_ENABLE_ERROR_REPORTING;
 +#endif
++                if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->vtable()->isString) {
++                    std::size_t heapBytes = static_cast<Heap::String *>(m)->retainedTextSize();
++                    Q_ASSERT(*unmanagedHeapSize >= heapBytes);
++//                    qDebug() << "-- it's a string holding on to" << heapBytes << "bytes";
++                    *unmanagedHeapSize -= heapBytes;
++                }
++
 +                if (m->vtable()->destroy)
 +                    m->vtable()->destroy(m);
 +
 +                memset(m, 0, header->itemSize);
 +#ifdef V4_USE_VALGRIND
 +                VALGRIND_DISABLE_ERROR_REPORTING;
 +                VALGRIND_MEMPOOL_FREE(engine->memoryManager, m);
 +#endif
 +                Q_V4_PROFILE_DEALLOC(engine, m, header->itemSize, Profiling::SmallItem);
 +                ++(*itemsInUse);
 +            }
 +            // Relink all free blocks to rewrite references to any released chunk.
 +            tail->setNextFree(m);
 +            tail = m;
 +        }
 +    }
 +    tail->setNextFree(0);
 +#ifdef V4_USE_VALGRIND
 +    VALGRIND_ENABLE_ERROR_REPORTING;
 +#endif
 +    return isEmpty;
 +}
 +
 +} // namespace
 +
 +MemoryManager::MemoryManager(ExecutionEngine *engine)
 +    : m_d(new Data)
 +    , m_persistentValues(new PersistentValueStorage(engine))
 +    , m_weakValues(new PersistentValueStorage(engine))
 +{
 +#ifdef V4_USE_VALGRIND
 +    VALGRIND_CREATE_MEMPOOL(this, 0, true);
 +#endif
 +    m_d->engine = engine;
 +}
 +
-         if (m_d->totalLargeItemsAllocated > 8 * 1024 * 1024)
++Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize)
 +{
 +    if (m_d->aggressiveGC)
 +        runGC();
 +#ifdef DETAILED_MM_STATS
 +    willAllocate(size);
 +#endif // DETAILED_MM_STATS
 +
 +    Q_ASSERT(size >= 16);
 +    Q_ASSERT(size % 16 == 0);
 +
++//    qDebug() << "unmanagedHeapSize:" << m_d->unmanagedHeapSize << "limit:" << m_d->unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
++    m_d->unmanagedHeapSize += unmanagedSize;
++    bool didGCRun = false;
++    if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) {
++        runGC();
++
++        if (m_d->unmanagedHeapSizeGCLimit <= m_d->unmanagedHeapSize)
++            m_d->unmanagedHeapSizeGCLimit = std::max(m_d->unmanagedHeapSizeGCLimit, m_d->unmanagedHeapSize) * 2;
++        else if (m_d->unmanagedHeapSize * 4 <= m_d->unmanagedHeapSizeGCLimit)
++            m_d->unmanagedHeapSizeGCLimit /= 2;
++        else if (m_d->unmanagedHeapSizeGCLimit - m_d->unmanagedHeapSize < 5 * unmanagedSize)
++            // try preventing running the GC all the time when we're just below the threshold limit and manage to collect just enough to do this one allocation
++            m_d->unmanagedHeapSizeGCLimit += std::max(std::size_t(8 * 1024), 5 * unmanagedSize);
++        didGCRun = true;
++    }
++
 +    size_t pos = size >> 4;
 +
 +    // doesn't fit into a small bucket
 +    if (size >= MemoryManager::Data::MaxItemSize) {
-     if (m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) {
++        if (!didGCRun && m_d->totalLargeItemsAllocated > 8 * 1024 * 1024)
 +            runGC();
 +
 +        // we use malloc for this
 +        MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(
 +                malloc(Q_V4_PROFILE_ALLOC(m_d->engine, size + sizeof(MemoryManager::Data::LargeItem),
 +                                          Profiling::LargeItem)));
 +        memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem));
 +        item->next = m_d->largeItems;
 +        item->size = size;
 +        m_d->largeItems = item;
 +        m_d->totalLargeItemsAllocated += size;
 +        return item->heapObject();
 +    }
 +
 +    Heap::Base *m = 0;
 +    Data::ChunkHeader *header = m_d->nonFullChunks[pos];
 +    if (header) {
 +        m = header->freeItems.nextFree();
 +        goto found;
 +    }
 +
 +    // try to free up space, otherwise allocate
-         chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], m_d->engine);
++    if (!didGCRun && m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) {
 +        runGC();
 +        header = m_d->nonFullChunks[pos];
 +        if (header) {
 +            m = header->freeItems.nextFree();
 +            goto found;
 +        }
 +    }
 +
 +    // no free item available, allocate a new chunk
 +    {
 +        // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default)
 +        uint shift = ++m_d->nChunks[pos];
 +        if (shift > m_d->maxShift)
 +            shift = m_d->maxShift;
 +        std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
 +        allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
 +        PageAllocation allocation = PageAllocation::allocate(
 +                    Q_V4_PROFILE_ALLOC(m_d->engine, allocSize, Profiling::HeapPage),
 +                    OSAllocator::JSGCHeapPages);
 +        m_d->heapChunks.append(allocation);
 +
 +        header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
 +        header->itemSize = int(size);
 +        header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
 +        header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
 +
 +        header->nextNonFull = m_d->nonFullChunks[pos];
 +        m_d->nonFullChunks[pos] = header;
 +
 +        Heap::Base *last = &header->freeItems;
 +        for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
 +            Heap::Base *o = reinterpret_cast<Heap::Base *>(item);
 +            last->setNextFree(o);
 +            last = o;
 +
 +        }
 +        last->setNextFree(0);
 +        m = header->freeItems.nextFree();
 +        const size_t increase = (header->itemEnd - header->itemStart) / header->itemSize;
 +        m_d->availableItems[pos] += uint(increase);
 +        m_d->totalItems += int(increase);
 +#ifdef V4_USE_VALGRIND
 +        VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize);
 +        VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader));
 +#endif
 +    }
 +
 +  found:
 +#ifdef V4_USE_VALGRIND
 +    VALGRIND_MEMPOOL_ALLOC(this, m, size);
 +#endif
 +    Q_V4_PROFILE_ALLOC(m_d->engine, size, Profiling::SmallItem);
 +
 +    ++m_d->allocCount[pos];
 +    ++m_d->totalAlloc;
 +    header->freeItems.setNextFree(m->nextFree());
 +    if (!header->freeItems.nextFree())
 +        m_d->nonFullChunks[pos] = header->nextNonFull;
 +    return m;
 +}
 +
 +static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
 +{
 +    while (engine->jsStackTop > markBase) {
 +        Heap::Base *h = engine->popForGC();
 +        Q_ASSERT (h->vtable()->markObjects);
 +        h->vtable()->markObjects(h, engine);
 +    }
 +}
 +
 +void MemoryManager::mark()
 +{
 +    Value *markBase = m_d->engine->jsStackTop;
 +
 +    m_d->engine->markObjects();
 +
 +    m_persistentValues->mark(m_d->engine);
 +
 +    collectFromJSStack();
 +
 +    // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
 +    // keeps all of its children alive in JavaScript.
 +
 +    // Do this _after_ collectFromStack to ensure that processing the weak
 +    // managed objects in the loop down there doesn't make then end up as leftovers
 +    // on the stack and thus always get collected.
 +    for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
 +        if (!(*it).isManaged())
 +            continue;
 +        if ((*it).managed()->d()->vtable() != QObjectWrapper::staticVTable())
 +            continue;
 +        QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed());
 +        QObject *qobject = qobjectWrapper->object();
 +        if (!qobject)
 +            continue;
 +        bool keepAlive = QQmlData::keepAliveDuringGarbageCollection(qobject);
 +
 +        if (!keepAlive) {
 +            if (QObject *parent = qobject->parent()) {
 +                while (parent->parent())
 +                    parent = parent->parent();
 +
 +                keepAlive = QQmlData::keepAliveDuringGarbageCollection(parent);
 +            }
 +        }
 +
 +        if (keepAlive)
 +            qobjectWrapper->mark(m_d->engine);
 +
 +        if (m_d->engine->jsStackTop >= m_d->engine->jsStackLimit)
 +            drainMarkStack(m_d->engine, markBase);
 +    }
 +
 +    drainMarkStack(m_d->engine, markBase);
 +}
 +
 +void MemoryManager::sweep(bool lastSweep)
 +{
 +    for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
 +        if (!(*it).isManaged())
 +            continue;
 +        Managed *m = (*it).as<Managed>();
 +        if (m->markBit())
 +            continue;
 +        // we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed
 +        // signal before we start sweeping the heap
 +        if ((*it).managed()->d()->vtable() == QObjectWrapper::staticVTable()) {
 +            QObjectWrapper *qobjectWrapper = static_cast<QObjectWrapper*>((*it).managed());
 +            qobjectWrapper->destroyObject(lastSweep);
 +        }
 +
 +        (*it) = Primitive::undefinedValue();
 +    }
 +
 +    if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) {
 +        for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
 +            if (!it.value().isNullOrUndefined())
 +                it = multiplyWrappedQObjects->erase(it);
 +            else
 +                ++it;
 +        }
 +    }
 +
 +    bool *chunkIsEmpty = (bool *)alloca(m_d->heapChunks.size() * sizeof(bool));
 +    uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
 +    memset(itemsInUse, 0, sizeof(itemsInUse));
 +    memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
 +
 +    for (int i = 0; i < m_d->heapChunks.size(); ++i) {
 +        Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
++        chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], m_d->engine, &m_d->unmanagedHeapSize);
 +    }
 +
 +    QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
 +    for (int i = 0; i < m_d->heapChunks.size(); ++i) {
 +        Q_ASSERT(chunkIter != m_d->heapChunks.end());
 +        Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
 +        const size_t pos = header->itemSize >> 4;
 +        const size_t decrease = (header->itemEnd - header->itemStart) / header->itemSize;
 +
 +        // Release that chunk if it could have been spared since the last GC run without any difference.
 +        if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
 +            Q_V4_PROFILE_DEALLOC(m_d->engine, 0, chunkIter->size(), Profiling::HeapPage);
 +#ifdef V4_USE_VALGRIND
 +            VALGRIND_MEMPOOL_FREE(this, header);
 +#endif
 +            --m_d->nChunks[pos];
 +            m_d->availableItems[pos] -= uint(decrease);
 +            m_d->totalItems -= int(decrease);
 +            chunkIter->deallocate();
 +            chunkIter = m_d->heapChunks.erase(chunkIter);
 +            continue;
 +        } else if (header->freeItems.nextFree()) {
 +            header->nextNonFull = m_d->nonFullChunks[pos];
 +            m_d->nonFullChunks[pos] = header;
 +        }
 +        ++chunkIter;
 +    }
 +
 +    Data::LargeItem *i = m_d->largeItems;
 +    Data::LargeItem **last = &m_d->largeItems;
 +    while (i) {
 +        Heap::Base *m = i->heapObject();
 +        Q_ASSERT(m->inUse());
 +        if (m->isMarked()) {
 +            m->clearMarkBit();
 +            last = &i->next;
 +            i = i->next;
 +            continue;
 +        }
 +        if (m->vtable()->destroy)
 +            m->vtable()->destroy(m);
 +
 +        *last = i->next;
 +        free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem),
 +                                  Profiling::LargeItem));
 +        i = *last;
 +    }
 +
 +    // some execution contexts are allocated on the stack, make sure we clear their markBit as well
 +    if (!lastSweep) {
 +        Heap::ExecutionContext *ctx = engine()->current;
 +        while (ctx) {
 +            ctx->clearMarkBit();
 +            ctx = ctx->parent;
 +        }
 +    }
 +}
 +
 +bool MemoryManager::isGCBlocked() const
 +{
 +    return m_d->gcBlocked;
 +}
 +
 +void MemoryManager::setGCBlocked(bool blockGC)
 +{
 +    m_d->gcBlocked = blockGC;
 +}
 +
 +void MemoryManager::runGC()
 +{
 +    if (m_d->gcBlocked) {
 +//        qDebug() << "Not running GC.";
 +        return;
 +    }
 +
 +    if (!m_d->gcStats) {
 +        mark();
 +        sweep();
 +    } else {
 +        const size_t totalMem = getAllocatedMem();
 +
 +        QTime t;
 +        t.start();
 +        mark();
 +        int markTime = t.elapsed();
 +        t.restart();
 +        const size_t usedBefore = getUsedMem();
 +        int chunksBefore = m_d->heapChunks.size();
 +        sweep();
 +        const size_t usedAfter = getUsedMem();
 +        int sweepTime = t.elapsed();
 +
 +        qDebug() << "========== GC ==========";
 +        qDebug() << "Marked object in" << markTime << "ms.";
 +        qDebug() << "Sweeped object in" << sweepTime << "ms.";
 +        qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks.";
 +        qDebug() << "Used memory before GC:" << usedBefore;
 +        qDebug() << "Used memory after GC:" << usedAfter;
 +        qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
 +        qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size());
 +        qDebug() << "======== End GC ========";
 +    }
 +
 +    memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
 +    m_d->totalAlloc = 0;
 +    m_d->totalLargeItemsAllocated = 0;
 +}
 +
 +size_t MemoryManager::getUsedMem() const
 +{
 +    size_t usedMem = 0;
 +    for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
 +        Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
 +        for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
 +            Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
 +            Q_ASSERT((qintptr) item % 16 == 0);
 +            if (m->inUse())
 +                usedMem += header->itemSize;
 +        }
 +    }
 +    return usedMem;
 +}
 +
 +size_t MemoryManager::getAllocatedMem() const
 +{
 +    size_t total = 0;
 +    for (int i = 0; i < m_d->heapChunks.size(); ++i)
 +        total += m_d->heapChunks.at(i).size();
 +    return total;
 +}
 +
 +size_t MemoryManager::getLargeItemsMem() const
 +{
 +    size_t total = 0;
 +    for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next)
 +        total += i->size;
 +    return total;
 +}
 +
++void MemoryManager::growUnmanagedHeapSizeUsage(size_t delta)
++{
++    m_d->unmanagedHeapSize += delta;
++}
++
 +MemoryManager::~MemoryManager()
 +{
 +    delete m_persistentValues;
 +
 +    sweep(/*lastSweep*/true);
 +
 +    delete m_weakValues;
 +#ifdef V4_USE_VALGRIND
 +    VALGRIND_DESTROY_MEMPOOL(this);
 +#endif
 +}
 +
 +ExecutionEngine *MemoryManager::engine() const
 +{
 +    return m_d->engine;
 +}
 +
 +void MemoryManager::dumpStats() const
 +{
 +#ifdef DETAILED_MM_STATS
 +    std::cerr << "=================" << std::endl;
 +    std::cerr << "Allocation stats:" << std::endl;
 +    std::cerr << "Requests for each chunk size:" << std::endl;
 +    for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) {
 +        if (unsigned count = m_d->allocSizeCounters[i]) {
 +            std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
 +        }
 +    }
 +#endif // DETAILED_MM_STATS
 +}
 +
 +#ifdef DETAILED_MM_STATS
 +void MemoryManager::willAllocate(std::size_t size)
 +{
 +    unsigned alignedSize = (size + 15) >> 4;
 +    QVector<unsigned> &counters = m_d->allocSizeCounters;
 +    if ((unsigned) counters.size() < alignedSize + 1)
 +        counters.resize(alignedSize + 1);
 +    counters[alignedSize]++;
 +}
 +
 +#endif // DETAILED_MM_STATS
 +
 +void MemoryManager::collectFromJSStack() const
 +{
 +    Value *v = m_d->engine->jsStackBase;
 +    Value *top = m_d->engine->jsStackTop;
 +    while (v < top) {
 +        Managed *m = v->as<Managed>();
 +        if (m && m->inUse())
 +            // Skip pointers to already freed objects, they are bogus as well
 +            m->mark(m_d->engine);
 +        ++v;
 +    }
 +}
 +QT_END_NAMESPACE
index 6d6ce1bad7a0e3b8a56b969f4970fb0d15722e74,0000000000000000000000000000000000000000..c01866ff1135c405a6b09277c597eb1c906cfe4c
mode 100644,000000..100644
--- /dev/null
@@@ -1,185 -1,0 +1,196 @@@
-     inline typename ManagedType::Data *allocManaged(std::size_t size)
 +/****************************************************************************
 +**
 +** Copyright (C) 2015 The Qt Company Ltd.
 +** Contact: http://www.qt.io/licensing/
 +**
 +** This file is part of the QtQml module of the Qt Toolkit.
 +**
 +** $QT_BEGIN_LICENSE:LGPL21$
 +** Commercial License Usage
 +** Licensees holding valid commercial Qt licenses may use this file in
 +** accordance with the commercial license agreement provided with the
 +** Software or, alternatively, in accordance with the terms contained in
 +** a written agreement between you and The Qt Company. For licensing terms
 +** and conditions see http://www.qt.io/terms-conditions. For further
 +** information use the contact form at http://www.qt.io/contact-us.
 +**
 +** GNU Lesser General Public License Usage
 +** Alternatively, this file may be used under the terms of the GNU Lesser
 +** General Public License version 2.1 or version 3 as published by the Free
 +** Software Foundation and appearing in the file LICENSE.LGPLv21 and
 +** LICENSE.LGPLv3 included in the packaging of this file. Please review the
 +** following information to ensure the GNU Lesser General Public License
 +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
 +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 +**
 +** As a special exception, The Qt Company gives you certain additional
 +** rights. These rights are described in The Qt Company LGPL Exception
 +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 +**
 +** $QT_END_LICENSE$
 +**
 +****************************************************************************/
 +
 +#ifndef QV4GC_H
 +#define QV4GC_H
 +
 +#include <private/qv4global_p.h>
 +#include <private/qv4value_p.h>
 +#include <private/qv4scopedvalue_p.h>
 +
 +//#define DETAILED_MM_STATS
 +
 +QT_BEGIN_NAMESPACE
 +
 +namespace QV4 {
 +
 +struct GCDeletable;
 +
 +class Q_QML_EXPORT MemoryManager
 +{
 +    Q_DISABLE_COPY(MemoryManager);
 +
 +public:
 +    struct Data;
 +
 +    class GCBlocker
 +    {
 +    public:
 +        GCBlocker(MemoryManager *mm)
 +            : mm(mm)
 +            , wasBlocked(mm->isGCBlocked())
 +        {
 +            mm->setGCBlocked(true);
 +        }
 +
 +        ~GCBlocker()
 +        {
 +            mm->setGCBlocked(wasBlocked);
 +        }
 +
 +    private:
 +        MemoryManager *mm;
 +        bool wasBlocked;
 +    };
 +
 +public:
 +    MemoryManager(ExecutionEngine *engine);
 +    ~MemoryManager();
 +
 +    // TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
 +    // Note: all occurrences of "16" in alloc/dealloc are also due to the alignment.
 +    static inline std::size_t align(std::size_t size)
 +    { return (size + 15) & ~0xf; }
 +
 +    template<typename ManagedType>
-         Heap::Base *o = allocData(size);
++    inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0)
 +    {
 +        size = align(size);
-     Heap::Base *allocData(std::size_t size);
++        Heap::Base *o = allocData(size, unmanagedSize);
 +        o->setVtable(ManagedType::staticVTable());
 +        return static_cast<typename ManagedType::Data *>(o);
 +    }
 +
 +    template <typename ManagedType>
 +    typename ManagedType::Data *alloc()
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data();
 +        return t->d();
 +    }
 +
 +    template <typename ManagedType, typename Arg1>
 +    typename ManagedType::Data *alloc(Arg1 arg1)
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data(arg1);
 +        return t->d();
 +    }
 +
++    template <typename ManagedType, typename Arg1>
++    typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
++    {
++        Scope scope(engine());
++        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize));
++        (void)new (t->d()) typename ManagedType::Data(this, arg1);
++        return t->d();
++    }
++
 +    template <typename ManagedType, typename Arg1, typename Arg2>
 +    typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2)
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data(arg1, arg2);
 +        return t->d();
 +    }
 +
 +    template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3>
 +    typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3)
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3);
 +        return t->d();
 +    }
 +
 +    template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
 +    typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4);
 +        return t->d();
 +    }
 +
 +    template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
 +    typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
 +    {
 +        Scope scope(engine());
 +        Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
 +        (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5);
 +        return t->d();
 +    }
 +
 +    bool isGCBlocked() const;
 +    void setGCBlocked(bool blockGC);
 +    void runGC();
 +
 +    ExecutionEngine *engine() const;
 +
 +    void dumpStats() const;
 +
 +    size_t getUsedMem() const;
 +    size_t getAllocatedMem() const;
 +    size_t getLargeItemsMem() const;
 +
++    void growUnmanagedHeapSizeUsage(size_t delta); // called when a JS object grows itself. Specifically: Heap::String::append
++
 +protected:
 +    /// expects size to be aligned
 +    // TODO: try to inline
++    Heap::Base *allocData(std::size_t size, std::size_t unmanagedSize);
 +
 +#ifdef DETAILED_MM_STATS
 +    void willAllocate(std::size_t size);
 +#endif // DETAILED_MM_STATS
 +
 +private:
 +    void collectFromJSStack() const;
 +    void mark();
 +    void sweep(bool lastSweep = false);
 +
 +protected:
 +    QScopedPointer<Data> m_d;
 +public:
 +    PersistentValueStorage *m_persistentValues;
 +    PersistentValueStorage *m_weakValues;
 +};
 +
 +}
 +
 +QT_END_NAMESPACE
 +
 +#endif // QV4GC_H
index f17009569f5b4f74b9a05dc5f7ce851ebcdb7196,f223d099e4e71e5914ca50cc874aaa4d2ecbca15..3613c1724230fc28e4714cf211d2cff93cfb255c
@@@ -43,7 -43,6 +43,8 @@@
  #include <private/qqmlscriptstring_p.h>
  #include <private/qqmlcontextwrapper_p.h>
  #include <private/qqmlbuiltinfunctions_p.h>
 +#include <private/qqmlvmemetaobject_p.h>
++#include <private/qqmlvaluetypewrapper_p.h>
  
  #include <QVariant>
  #include <QtCore/qdebug.h>
@@@ -152,210 -167,59 +153,215 @@@ void QQmlBinding::update(QQmlPropertyPr
  
      QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
      QV4::Scope scope(ep->v4engine());
 -    QV4::ScopedFunctionObject f(scope, v4function.value());
 +    QV4::ScopedFunctionObject f(scope, m_function.value());
      Q_ASSERT(f);
  
 -    if (!updatingFlag()) {
 -        QQmlBindingProfiler prof(ep->profiler, f);
 -        setUpdatingFlag(true);
 +    if (updatingFlag()) {
 +        QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0);
 +        QQmlAbstractBinding::printBindingLoopError(p);
 +        return;
 +    }
 +
 +    QQmlBindingProfiler prof(ep->profiler, f);
 +    setUpdatingFlag(true);
  
 -        QQmlAbstractExpression::DeleteWatcher watcher(this);
 +    QQmlJavaScriptExpression::DeleteWatcher watcher(this);
  
 -        if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {
 +    QQmlPropertyData pd = getPropertyData();
  
 -            int idx = m_core.coreIndex;
 -            Q_ASSERT(idx != -1);
 +    if (pd.propType == qMetaTypeId<QQmlBinding *>()) {
  
 -            QQmlBinding *t = this;
 -            int status = -1;
 -            void *a[] = { &t, 0, &status, &flags };
 -            QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);
 +        int idx = pd.coreIndex;
 +        Q_ASSERT(idx != -1);
  
 -        } else {
 -            ep->referenceScarceResources();
 +        QQmlBinding *t = this;
 +        int status = -1;
 +        void *a[] = { &t, 0, &status, &flags };
 +        QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a);
  
 -            bool isUndefined = false;
 +    } else {
 +        ep->referenceScarceResources();
  
 -            QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined));
 +        bool isUndefined = false;
  
 -            bool needsErrorLocationData = false;
 -            if (!watcher.wasDeleted() && !hasError())
 -                needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
 -                                                                    this, result, isUndefined, flags);
 +        QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
  
 -            if (!watcher.wasDeleted()) {
 +        bool error = false;
 +        if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
 +            error = !write(pd, result, isUndefined, flags);
  
 -                if (needsErrorLocationData)
 -                    delayedError()->setErrorLocation(f->sourceLocation());
 +        if (!watcher.wasDeleted()) {
  
 -                if (hasError()) {
 -                    if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
 -                } else {
 -                    clearError();
 -                }
 +            if (error) {
 +                delayedError()->setErrorLocation(f->sourceLocation());
 +                delayedError()->setErrorObject(m_target.data());
 +            }
  
 +            if (hasError()) {
 +                if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
 +            } else {
 +                clearError();
              }
  
 -            ep->dereferenceScarceResources();
          }
  
 -        if (!watcher.wasDeleted())
 -            setUpdatingFlag(false);
 -    } else {
 -        QQmlProperty p = property();
 -        QQmlAbstractBinding::printBindingLoopError(p);
 +        ep->dereferenceScarceResources();
      }
-             if (QObject *o = *(QObject **)value.constData()) {
 +
 +    if (!watcher.wasDeleted())
 +        setUpdatingFlag(false);
 +}
 +
 +// Returns true if successful, false if an error description was set on expression
 +bool QQmlBinding::write(const QQmlPropertyData &core,
 +                       const QV4::Value &result, bool isUndefined,
 +                       QQmlPropertyPrivate::WriteFlags flags)
 +{
 +    Q_ASSERT(m_target.data());
 +    Q_ASSERT(core.coreIndex != -1);
 +
 +    QQmlEngine *engine = context()->engine;
 +    QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
 +
 +#define QUICK_STORE(cpptype, conversion) \
 +        { \
 +            cpptype o = (conversion); \
 +            int status = -1; \
 +            void *argv[] = { &o, 0, &status, &flags }; \
 +            QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \
 +            return true; \
 +        } \
 +
 +
 +    if (!isUndefined && !core.isValueTypeVirtual()) {
 +        switch (core.propType) {
 +        case QMetaType::Int:
 +            if (result.isInteger())
 +                QUICK_STORE(int, result.integerValue())
 +            else if (result.isNumber())
 +                QUICK_STORE(int, result.doubleValue())
 +            break;
 +        case QMetaType::Double:
 +            if (result.isNumber())
 +                QUICK_STORE(double, result.asDouble())
 +            break;
 +        case QMetaType::Float:
 +            if (result.isNumber())
 +                QUICK_STORE(float, result.asDouble())
 +            break;
 +        case QMetaType::QString:
 +            if (result.isString())
 +                QUICK_STORE(QString, result.toQStringNoThrow())
 +            break;
 +        default:
++            if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
++                if (vtw->d()->valueType->typeId == core.propType) {
++                    return vtw->write(m_target.data(), core.coreIndex);
++                }
++            }
 +            break;
 +        }
 +    }
 +#undef QUICK_STORE
 +
 +    int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType;
 +
 +    QQmlJavaScriptExpression::DeleteWatcher watcher(this);
 +
 +    QVariant value;
 +    bool isVarProperty = core.isVarProperty();
 +
 +    if (isUndefined) {
 +    } else if (core.isQList()) {
 +        value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >());
 +    } else if (result.isNull() && core.isQObject()) {
 +        value = QVariant::fromValue((QObject *)0);
 +    } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
 +        value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context());
 +    } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
 +        value = QV8Engine::getV4(v8engine)->toVariant(result, type);
 +    }
 +
 +    if (hasError()) {
 +        return false;
 +    } else if (isVarProperty) {
 +        const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
 +        if (f && f->isBinding()) {
 +            // we explicitly disallow this case to avoid confusion.  Users can still store one
 +            // in an array in a var property if they need to, but the common case is user error.
 +            delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 +            return false;
 +        }
 +
 +        QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
 +        Q_ASSERT(vmemo);
 +        vmemo->setVMEProperty(core.coreIndex, result);
 +    } else if (isUndefined && core.isResettable()) {
 +        void *args[] = { 0 };
 +        QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args);
 +    } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
 +        QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags);
 +    } else if (type == qMetaTypeId<QJSValue>()) {
 +        const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
 +        if (f && f->isBinding()) {
 +            delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 +            return false;
 +        }
 +        QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue(
 +                               QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())),
 +                           context(), flags);
 +    } else if (isUndefined) {
 +        QString errorStr = QLatin1String("Unable to assign [undefined] to ");
 +        if (!QMetaType::typeName(type))
 +            errorStr += QLatin1String("[unknown property type]");
 +        else
 +            errorStr += QLatin1String(QMetaType::typeName(type));
 +        delayedError()->setErrorDescription(errorStr);
 +        return false;
 +    } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
 +        if (f->isBinding())
 +            delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 +        else
 +            delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
 +        return false;
 +    } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) {
 +
 +        if (watcher.wasDeleted())
 +            return true;
 +
 +        const char *valueType = 0;
 +        const char *propertyType = 0;
 +
 +        if (value.userType() == QMetaType::QObjectStar) {
++            if (QObject *o = *(QObject *const *)value.constData()) {
 +                valueType = o->metaObject()->className();
 +
 +                QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
 +                if (!propertyMetaObject.isNull())
 +                    propertyType = propertyMetaObject.className();
 +            }
 +        } else if (value.userType() != QVariant::Invalid) {
 +            if (value.userType() == QMetaType::VoidStar)
 +                valueType = "null";
 +            else
 +                valueType = QMetaType::typeName(value.userType());
 +        }
 +
 +        if (!valueType)
 +            valueType = "undefined";
 +        if (!propertyType)
 +            propertyType = QMetaType::typeName(type);
 +        if (!propertyType)
 +            propertyType = "[unknown property type]";
 +
 +        delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
 +                                                        QLatin1String(valueType) +
 +                                                        QLatin1String(" to ") +
 +                                                        QLatin1String(propertyType));
 +        return false;
 +    }
 +
 +    return true;
  }
  
  QVariant QQmlBinding::evaluate()
Simple merge
Simple merge
Simple merge
Simple merge
index bd2c0e65067681dd2627bf67008200422bc22953,2742bfc84b9e3d3209ce94e949c47b77656f0dcc..90902c089d2d5a7fa1d83b8a5c9a36b3ef7d9c9b
@@@ -60,7 -60,12 +60,9 @@@ private
  class QQmlEngine;
  class QQmlNotifierEndpoint
  {
+     QQmlNotifierEndpoint  *next;
+     QQmlNotifierEndpoint **prev;
  public:
 -    inline QQmlNotifierEndpoint();
 -    inline ~QQmlNotifierEndpoint();
 -
      // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks.
      // To add another callback, extend this enum and add the callback to the top
      // of qqmlnotifier.cpp.  Four bits are reserved for the callback, so there can
@@@ -136,8 -135,8 +135,8 @@@ void QQmlNotifier::notify(
      if (endpoints) emitNotify(endpoints, args);
  }
  
 -QQmlNotifierEndpoint::QQmlNotifierEndpoint()
 -: next(0), prev(0), senderPtr(0), callback(None), sourceSignal(-1)
 +QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback)
- : senderPtr(0), callback(callback), sourceSignal(-1), next(0), prev(0)
++: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1)
  {
  }
  
index 414bf8fe0f182eea2a7e93db22d5daf2d4f02f7b,800f6500757409cea95780642229b5a1f3adc3df..c1120b4542903bdaec100529a183dc1572cf6082
@@@ -1411,7 -1475,166 +1411,6 @@@ bool QQmlPropertyPrivate::write(QObjec
      return true;
  }
  
 -// Returns true if successful, false if an error description was set on expression
 -bool QQmlPropertyPrivate::writeBinding(QObject *object,
 -                                               const QQmlPropertyData &core,
 -                                               QQmlContextData *context,
 -                                               QQmlJavaScriptExpression *expression,
 -                                               const QV4::Value &result, bool isUndefined,
 -                                               WriteFlags flags)
 -{
 -    Q_ASSERT(object);
 -    Q_ASSERT(core.coreIndex != -1);
 -
 -    QQmlEngine *engine = context->engine;
 -    QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine);
 -
 -#define QUICK_STORE(cpptype, conversion) \
 -        { \
 -            cpptype o = (conversion); \
 -            int status = -1; \
 -            void *argv[] = { &o, 0, &status, &flags }; \
 -            QMetaObject::metacall(object, QMetaObject::WriteProperty, core.coreIndex, argv); \
 -            return true; \
 -        } \
 -
 -
 -    if (!isUndefined && !core.isValueTypeVirtual()) {
 -        switch (core.propType) {
 -        case QMetaType::Int:
 -            if (result.isInteger())
 -                QUICK_STORE(int, result.integerValue())
 -            else if (result.isNumber())
 -                QUICK_STORE(int, result.doubleValue())
 -            break;
 -        case QMetaType::Double:
 -            if (result.isNumber())
 -                QUICK_STORE(double, result.asDouble())
 -            break;
 -        case QMetaType::Float:
 -            if (result.isNumber())
 -                QUICK_STORE(float, result.asDouble())
 -            break;
 -        case QMetaType::QString:
 -            if (result.isString())
 -                QUICK_STORE(QString, result.toQStringNoThrow())
 -            break;
 -        default:
 -            if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
 -                if (vtw->d()->valueType->typeId == core.propType) {
 -                    return vtw->write(object, core.coreIndex);
 -                }
 -            }
 -            break;
 -        }
 -    }
 -#undef QUICK_STORE
 -
 -    int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType;
 -
 -    QQmlJavaScriptExpression::DeleteWatcher watcher(expression);
 -
 -    QVariant value;
 -    bool isVarProperty = core.isVarProperty();
 -
 -    if (isUndefined) {
 -    } else if (core.isQList()) {
 -        value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >());
 -    } else if (result.isNull() && core.isQObject()) {
 -        value = QVariant::fromValue((QObject *)0);
 -    } else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
 -        value = resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
 -    } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
 -        value = QV8Engine::getV4(v8engine)->toVariant(result, type);
 -    }
 -
 -    if (expression->hasError()) {
 -        return false;
 -    } else if (isVarProperty) {
 -        QV4::FunctionObject *f = result.asFunctionObject();
 -        if (f && f->isBinding()) {
 -            // we explicitly disallow this case to avoid confusion.  Users can still store one
 -            // in an array in a var property if they need to, but the common case is user error.
 -            expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 -            expression->delayedError()->setErrorObject(object);
 -            return false;
 -        }
 -
 -        QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
 -        Q_ASSERT(vmemo);
 -        vmemo->setVMEProperty(core.coreIndex, result);
 -    } else if (isUndefined && core.isResettable()) {
 -        void *args[] = { 0 };
 -        QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args);
 -    } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
 -        writeValueProperty(object, core, QVariant(), context, flags);
 -    } else if (type == qMetaTypeId<QJSValue>()) {
 -        QV4::FunctionObject *f = result.asFunctionObject();
 -        if (f && f->isBinding()) {
 -            expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 -            expression->delayedError()->setErrorObject(object);
 -            return false;
 -        }
 -        writeValueProperty(object, core, QVariant::fromValue(
 -                               QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())),
 -                           context, flags);
 -    } else if (isUndefined) {
 -        QString errorStr = QLatin1String("Unable to assign [undefined] to ");
 -        if (!QMetaType::typeName(type))
 -            errorStr += QLatin1String("[unknown property type]");
 -        else
 -            errorStr += QLatin1String(QMetaType::typeName(type));
 -        expression->delayedError()->setErrorDescription(errorStr);
 -        expression->delayedError()->setErrorObject(object);
 -        return false;
 -    } else if (QV4::FunctionObject *f = result.asFunctionObject()) {
 -        if (f->isBinding())
 -            expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
 -        else
 -            expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
 -        expression->delayedError()->setErrorObject(object);
 -        return false;
 -    } else if (!writeValueProperty(object, core, value, context, flags)) {
 -
 -        if (watcher.wasDeleted())
 -            return true;
 -
 -        const char *valueType = 0;
 -        const char *propertyType = 0;
 -
 -        if (value.userType() == QMetaType::QObjectStar) {
 -            if (QObject *o = *(QObject *const *)value.constData()) {
 -                valueType = o->metaObject()->className();
 -
 -                QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
 -                if (!propertyMetaObject.isNull())
 -                    propertyType = propertyMetaObject.className();
 -            }
 -        } else if (value.userType() != QVariant::Invalid) {
 -            if (value.userType() == QMetaType::VoidStar)
 -                valueType = "null";
 -            else
 -                valueType = QMetaType::typeName(value.userType());
 -        }
 -
 -        if (!valueType)
 -            valueType = "undefined";
 -        if (!propertyType)
 -            propertyType = QMetaType::typeName(type);
 -        if (!propertyType)
 -            propertyType = "[unknown property type]";
 -
 -        expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
 -                                                        QLatin1String(valueType) +
 -                                                        QLatin1String(" to ") +
 -                                                        QLatin1String(propertyType));
 -        expression->delayedError()->setErrorObject(object);
 -        return false;
 -    }
 -
 -    return true;
 -}
--
  QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
  {
      QMetaType metaType(userType);
Simple merge
Simple merge
Simple merge
Simple merge
index fc4a3efb8e774c77c6f09bc7e2fedae6cbda4ac1,19fb66c19c6817313938b45ade5ae2a9e1ebbdd7..ea4398bc7172f80d33d55a72e0d7693c020d6014
@@@ -1433,8 -1450,7 +1450,8 @@@ void QQuickFlickable::wheelEvent(QWheel
          QVector2D velocity(xDelta / elapsed, yDelta / elapsed);
          d->lastPosTime = currentTimestamp;
          d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta());
-         d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, velocity);
+         d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity);
 +        event->accept();
      }
  
      if (!event->isAccepted())
Simple merge
Simple merge
Simple merge
Simple merge
index b08a8cfffedd1833c842a501d053e88f070b84da,20b6dd5b36ac52b71b4b6919e786c6603bc0bc3d..a1d765d6ec04b1e2c91ed7192440974a0aa56ffb
@@@ -267,20 -267,20 +267,20 @@@ public
      }
      qreal itemPosition() const {
          if (view->orientation() == QQuickListView::Vertical)
 -            return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY());
 +            return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemHeight()-itemY() : itemY());
          else
 -            return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
 +            return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemWidth()-itemX() : itemX());
      }
-     qreal size() const {
+     qreal size() const Q_DECL_OVERRIDE {
          if (section())
 -            return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width());
 +            return (view->orientation() == QQuickListView::Vertical ? itemHeight()+section()->height() : itemWidth()+section()->width());
          else
 -            return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
 +            return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth());
      }
      qreal itemSize() const {
 -        return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
 +        return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth());
      }
-     qreal sectionSize() const {
+     qreal sectionSize() const Q_DECL_OVERRIDE {
          if (section())
              return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width());
          return 0.0;
Simple merge
Simple merge
Simple merge
index cf7e91ffec10963fae22dba57c74d7012417e6e5,cd1cf5eef12a85e9e917e644714963ea014f792b..dc4e301a36205f98229f5e434f52dcdfa6c99046
@@@ -1957,17 -1869,10 +1957,10 @@@ QSGNode *QQuickTextEdit::updatePaintNod
                  ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout());
                  QTextCharFormat format = a->formatAccessor(pos);
                  QTextBlock block = textFrame->firstCursorPosition().block();
 -                node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
 -                node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
 +                engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
 +                engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
                                                pos, textFrame->frameFormat().position());
                  nodeStart = pos;
-             } else if (qobject_cast<QTextTable*>(textFrame)) { // To keep things simple, map text tables as one text node
-                 QTextFrame::iterator it = textFrame->begin();
-                 nodeOffset =  d->document->documentLayout()->frameBoundingRect(textFrame).topLeft();
-                 updateNodeTransform(node, nodeOffset);
-                 while (!it.atEnd())
-                     engine.addTextBlock(d->document, (it++).currentBlock(), -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
-                 nodeStart = textFrame->firstPosition();
              } else {
                  // Having nodes spanning across frame boundaries will break the current bookkeeping mechanism. We need to prevent that.
                  QList<int> frameBoundaries;
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 9682070162cd8fe51186ced43dcd40cb4da498fd,d87054ac9e42e90a5e025cde05a716d29fa6c34f..079f73ae34ea9ff7f67c78325d6c84f70537d2f1
@@@ -2411,15 -2409,15 +2411,15 @@@ void tst_qquicktextinput::navigation(
      input->select(0,input->text().length());
      QVERIFY(input->selectionStart() != input->selectionEnd());
      simulateKey(&window, Qt::Key_Right);
 -    QVERIFY(input->selectionStart() == input->selectionEnd());
 -    QVERIFY(input->selectionStart() == input->text().length());
 -    QVERIFY(input->hasActiveFocus() == true);
 +    QCOMPARE(input->selectionStart(), input->selectionEnd());
 +    QCOMPARE(input->selectionStart(), input->text().length());
 +    QVERIFY(input->hasActiveFocus());
      simulateKey(&window, Qt::Key_Right);
 -    QVERIFY(input->hasActiveFocus() == false);
 +    QVERIFY(!input->hasActiveFocus());
      simulateKey(&window, Qt::Key_Left);
 -    QVERIFY(input->hasActiveFocus() == true);
 +    QVERIFY(input->hasActiveFocus());
  
-     // Up and Down should NOT do Home/End, even on Mac OS X (QTBUG-10438).
+     // Up and Down should NOT do Home/End, even on OS X (QTBUG-10438).
      input->setCursorPosition(2);
      QCOMPARE(input->cursorPosition(),2);
      simulateKey(&window, Qt::Key_Up);
index 4bebd74579ec2b4c205c4cb0f17ee315e64bffc6,e9298f226a5e5fc9228fb55554e52ce51948d174..72e11eadec713a57932ceb64d24d713ae8cdb032
  
  #include <QtCore/QStack>
  #include <QtCore/QStringList>
 +#include <QtCore/QDataStream>
  
+ #include <limits>
  ProfilerClient::ProfilerClient(const QString &clientName,
                               QQmlDebugConnection *client)
      : QQmlDebugClient(clientName, client),
Simple merge