diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..183f5b46cc1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/3rdparty/v8"] + path = src/3rdparty/v8 + url = git://github.com/aaronkennedy/v8.git diff --git a/bin/syncqt b/bin/syncqt index 4eab929b309..f28b2bf60a1 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -33,7 +33,7 @@ $qtbasedir = dirname(dirname($0)) if (!$qtbasedir); $qtbasedir =~ s=\\=/=g if (defined $qtbasedir); # will be defined based on the modules sync.profile -our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris); +our (%modules, %moduleheaders, @allmoduleheadersprivate, %classnames, %mastercontent, %modulepris); # global variables (modified by options) my $isunix = 0; @@ -792,6 +792,8 @@ loadSyncProfile(\$basedir, \$out_basedir); @modules_to_sync = keys(%modules) if($#modules_to_sync == -1); +my %allmoduleheadersprivate = map { $_ => 1 } @allmoduleheadersprivate; + $isunix = checkUnix; #cache checkUnix # create path @@ -828,6 +830,9 @@ foreach my $lib (@modules_to_sync) { my $pathtoheaders = ""; $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib}); + my $allheadersprivate = 0; + $allheadersprivate = 1 if $allmoduleheadersprivate{$lib}; + #information used after the syncing my $pri_install_classes = ""; my $pri_install_files = ""; @@ -955,7 +960,7 @@ foreach my $lib (@modules_to_sync) { my $header_copies = 0; #figure out if it is a public header my $public_header = $header; - if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) { + if($allheadersprivate || $public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) { $public_header = 0; } else { foreach (@ignore_for_master_contents) { diff --git a/config.tests/x11/fontconfig/fontconfig.pro b/config.tests/x11/fontconfig/fontconfig.pro index 718a8204bc7..83607740355 100644 --- a/config.tests/x11/fontconfig/fontconfig.pro +++ b/config.tests/x11/fontconfig/fontconfig.pro @@ -1,5 +1,4 @@ SOURCES = fontconfig.cpp -CONFIG += x11 CONFIG -= qt LIBS += -lfreetype -lfontconfig include(../../unix/freetype/freetype.pri) diff --git a/configure b/configure index 7f8491ed703..6a7027e46a5 100755 --- a/configure +++ b/configure @@ -706,6 +706,7 @@ CFG_PHONON_BACKEND=yes CFG_MULTIMEDIA=auto CFG_AUDIO_BACKEND=auto CFG_SVG=auto +CFG_V8=auto CFG_DECLARATIVE=auto CFG_DECLARATIVE_DEBUG=yes CFG_WEBKIT=auto # (yes|no|auto|debug) @@ -2122,6 +2123,17 @@ while [ "$#" -gt 0 ]; do fi fi ;; + v8) + if [ "$VAL" = "yes" ]; then + CFG_V8="yes" + else + if [ "$VAL" = "no" ]; then + CFG_V8="no" + else + UNKNOWN_OPT=yes + fi + fi + ;; declarative) if [ "$VAL" = "yes" ]; then CFG_DECLARATIVE="yes" @@ -3896,6 +3908,9 @@ fi -no-scripttools .... Do not build the QtScriptTools module. + -scripttools ....... Build the QtScriptTools module. + -no-v8 ............. Do not build the V8 module. + + -v8 ................ Build the V8 module. + -no-declarative ..... Do not build the declarative module. + -declarative ....... Build the declarative module. @@ -7579,9 +7594,19 @@ fi #fi +if [ "$CFG_V8" = "auto" ]; then + CFG_V8=yes +fi + +if [ "$CFG_V8" = "no" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_V8" +else + QT_CONFIG="$QT_CONFIG v8" +fi + if [ "$CFG_DECLARATIVE" = "yes" ]; then - if [ "$CFG_SCRIPT" = "no" -o "$CFG_GUI" = "no" ]; then - echo "Error: QtDeclarative was requested, but it can't be built due to QtScript or QtGui being disabled." + if [ "$CFG_V8" = "no" -o "$CFG_GUI" = "no" ]; then + echo "Error: QtDeclarative was requested, but it can't be built due to QtV8 or QtGui being disabled." exit 1 fi fi @@ -8629,6 +8654,7 @@ if [ "$CFG_WEBKIT" != "no" ] || [ "$CFG_SCRIPT" != "no" ]; then echo "JavaScriptCore JIT ..... $CFG_JAVASCRIPTCORE_JIT" fi fi +echo "V8 module .............. $CFG_V8" echo "Declarative module ..... $CFG_DECLARATIVE" if [ "$CFG_DECLARATIVE" = "yes" ]; then echo "Declarative debugging ...$CFG_DECLARATIVE_DEBUG" diff --git a/src/3rdparty/v8 b/src/3rdparty/v8 new file mode 160000 index 00000000000..dc2cad4f8fc --- /dev/null +++ b/src/3rdparty/v8 @@ -0,0 +1 @@ +Subproject commit dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44 diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 2d280f14f76..0f314d45f16 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -147,6 +147,7 @@ private: void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0; +void (*QAbstractDeclarativeData::signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **) = 0; QObjectData::~QObjectData() {} @@ -3271,6 +3272,10 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign int signal_index = signalOffset + local_signal_index; + if (sender->d_func()->declarativeData && QAbstractDeclarativeData::signalEmitted) + QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender, + methodOffset + local_signal_index, argv); + if (!sender->d_func()->isSignalConnected(signal_index)) return; // nothing connected to these signals, and no spy diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 9151e8eb7b4..e7233c5ba9a 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -91,6 +91,7 @@ public: static void (*destroyed)(QAbstractDeclarativeData *, QObject *); static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *); static void (*objectNameChanged)(QAbstractDeclarativeData *, QObject *); + static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **); }; class Q_CORE_EXPORT QObjectPrivate : public QObjectData diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index cef92af66ba..1797564a98d 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -209,7 +209,7 @@ QMatrix4x4::QMatrix4x4(const QMatrix& matrix) m[3][1] = matrix.dy(); m[3][2] = 0.0f; m[3][3] = 1.0f; - flagBits = General; + flagBits = Translation | Scale | Rotation2D; } /*! @@ -316,6 +316,12 @@ QMatrix4x4::QMatrix4x4(const QTransform& transform) Fills all elements of this matrx with \a value. */ +static inline qreal matrixDet2(const qreal m[4][4], int col0, int col1, int row0, int row1) +{ + return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0]; +} + + // The 4x4 matrix inverse algorithm is based on that described at: // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24 // Some optimization has been done to avoid making copies of 3x3 @@ -329,15 +335,9 @@ static inline qreal matrixDet3 (const qreal m[4][4], int col0, int col1, int col2, int row0, int row1, int row2) { - return m[col0][row0] * - (m[col1][row1] * m[col2][row2] - - m[col1][row2] * m[col2][row1]) - - m[col1][row0] * - (m[col0][row1] * m[col2][row2] - - m[col0][row2] * m[col2][row1]) + - m[col2][row0] * - (m[col0][row1] * m[col1][row2] - - m[col0][row2] * m[col1][row1]); + return m[col0][row0] * matrixDet2(m, col1, col2, row1, row2) + - m[col1][row0] * matrixDet2(m, col0, col2, row1, row2) + + m[col2][row0] * matrixDet2(m, col0, col1, row1, row2); } // Calculate the determinant of a 4x4 matrix. @@ -356,7 +356,13 @@ static inline qreal matrixDet4(const qreal m[4][4]) */ qreal QMatrix4x4::determinant() const { - return qreal(matrixDet4(m)); + if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) + return 1; + if (flagBits < Rotation2D) + return m[0][0] * m[1][1] * m[2][2]; // Translation | Scale + if (flagBits < Perspective) + return matrixDet3(m, 0, 1, 2, 0, 1, 2); + return matrixDet4(m); } /*! @@ -387,10 +393,61 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const if (invertible) *invertible = true; return inv; - } else if (flagBits == Rotation || flagBits == (Rotation | Translation)) { + } else if (flagBits < Rotation2D) { + // Translation | Scale + if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) { + if (invertible) + *invertible = false; + return QMatrix4x4(); + } + QMatrix4x4 inv; + inv.m[0][0] = 1.0f / m[0][0]; + inv.m[1][1] = 1.0f / m[1][1]; + inv.m[2][2] = 1.0f / m[2][2]; + inv.m[3][0] = -m[3][0] * inv.m[0][0]; + inv.m[3][1] = -m[3][1] * inv.m[1][1]; + inv.m[3][2] = -m[3][2] * inv.m[2][2]; + inv.flagBits = flagBits; + + if (invertible) + *invertible = true; + return inv; + } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) { if (invertible) *invertible = true; return orthonormalInverse(); + } else if (flagBits < Perspective) { + QMatrix4x4 inv(1); // The "1" says to not load the identity. + + qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2); + if (det == 0.0f) { + if (invertible) + *invertible = false; + return QMatrix4x4(); + } + det = 1.0f / det; + + inv.m[0][0] = matrixDet2(m, 1, 2, 1, 2) * det; + inv.m[0][1] = -matrixDet2(m, 0, 2, 1, 2) * det; + inv.m[0][2] = matrixDet2(m, 0, 1, 1, 2) * det; + inv.m[0][3] = 0; + inv.m[1][0] = -matrixDet2(m, 1, 2, 0, 2) * det; + inv.m[1][1] = matrixDet2(m, 0, 2, 0, 2) * det; + inv.m[1][2] = -matrixDet2(m, 0, 1, 0, 2) * det; + inv.m[1][3] = 0; + inv.m[2][0] = matrixDet2(m, 1, 2, 0, 1) * det; + inv.m[2][1] = -matrixDet2(m, 0, 2, 0, 1) * det; + inv.m[2][2] = matrixDet2(m, 0, 1, 0, 1) * det; + inv.m[2][3] = 0; + inv.m[3][0] = -inv.m[0][0] * m[3][0] - inv.m[1][0] * m[3][1] - inv.m[2][0] * m[3][2]; + inv.m[3][1] = -inv.m[0][1] * m[3][0] - inv.m[1][1] * m[3][1] - inv.m[2][1] * m[3][2]; + inv.m[3][2] = -inv.m[0][2] * m[3][0] - inv.m[1][2] * m[3][1] - inv.m[2][2] * m[3][2]; + inv.m[3][3] = 1; + inv.flagBits = flagBits; + + if (invertible) + *invertible = true; + return inv; } QMatrix4x4 inv(1); // The "1" says to not load the identity. @@ -419,6 +476,7 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const inv.m[3][1] = matrixDet3(m, 0, 2, 3, 0, 1, 2) * det; inv.m[3][2] = -matrixDet3(m, 0, 1, 3, 0, 1, 2) * det; inv.m[3][3] = matrixDet3(m, 0, 1, 2, 0, 1, 2) * det; + inv.flagBits = flagBits; if (invertible) *invertible = true; @@ -438,15 +496,29 @@ QMatrix3x3 QMatrix4x4::normalMatrix() const QMatrix3x3 inv; // Handle the simple cases first. - if (flagBits == Identity || flagBits == Translation) { + if (flagBits < Scale) { + // Translation return inv; - } else if (flagBits == Scale || flagBits == (Translation | Scale)) { + } else if (flagBits < Rotation2D) { + // Translation | Scale if (m[0][0] == 0.0f || m[1][1] == 0.0f || m[2][2] == 0.0f) return inv; inv.data()[0] = 1.0f / m[0][0]; inv.data()[4] = 1.0f / m[1][1]; inv.data()[8] = 1.0f / m[2][2]; return inv; + } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) { + qreal *invm = inv.data(); + invm[0 + 0 * 3] = m[0][0]; + invm[1 + 0 * 3] = m[0][1]; + invm[2 + 0 * 3] = m[0][2]; + invm[0 + 1 * 3] = m[1][0]; + invm[1 + 1 * 3] = m[1][1]; + invm[2 + 1 * 3] = m[1][2]; + invm[0 + 2 * 3] = m[2][0]; + invm[1 + 2 * 3] = m[2][1]; + invm[2 + 2 * 3] = m[2][2]; + return inv; } qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2); @@ -481,6 +553,8 @@ QMatrix4x4 QMatrix4x4::transposed() const result.m[col][row] = m[row][col]; } } + // When a translation is transposed, it becomes a perspective transformation. + result.flagBits = (flagBits & Translation ? General : flagBits); return result; } @@ -689,6 +763,7 @@ QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor) m.m[3][1] = matrix.m[3][1] / divisor; m.m[3][2] = matrix.m[3][2] / divisor; m.m[3][3] = matrix.m[3][3] / divisor; + m.flagBits = QMatrix4x4::General; return m; } @@ -713,20 +788,20 @@ void QMatrix4x4::scale(const QVector3D& vector) qreal vx = vector.x(); qreal vy = vector.y(); qreal vz = vector.z(); - if (flagBits == Identity) { + if (flagBits < Scale) { m[0][0] = vx; m[1][1] = vy; m[2][2] = vz; - flagBits = Scale; - } else if (flagBits == Scale || flagBits == (Scale | Translation)) { + } else if (flagBits < Rotation2D) { m[0][0] *= vx; m[1][1] *= vy; m[2][2] *= vz; - } else if (flagBits == Translation) { - m[0][0] = vx; - m[1][1] = vy; - m[2][2] = vz; - flagBits |= Scale; + } else if (flagBits < Rotation) { + m[0][0] *= vx; + m[0][1] *= vx; + m[1][0] *= vy; + m[1][1] *= vy; + m[2][2] *= vz; } else { m[0][0] *= vx; m[0][1] *= vx; @@ -740,9 +815,10 @@ void QMatrix4x4::scale(const QVector3D& vector) m[2][1] *= vz; m[2][2] *= vz; m[2][3] *= vz; - flagBits = General; } + flagBits |= Scale; } + #endif /*! @@ -755,17 +831,17 @@ void QMatrix4x4::scale(const QVector3D& vector) */ void QMatrix4x4::scale(qreal x, qreal y) { - if (flagBits == Identity) { + if (flagBits < Scale) { m[0][0] = x; m[1][1] = y; - flagBits = Scale; - } else if (flagBits == Scale || flagBits == (Scale | Translation)) { + } else if (flagBits < Rotation2D) { m[0][0] *= x; m[1][1] *= y; - } else if (flagBits == Translation) { - m[0][0] = x; - m[1][1] = y; - flagBits |= Scale; + } else if (flagBits < Rotation) { + m[0][0] *= x; + m[0][1] *= x; + m[1][0] *= y; + m[1][1] *= y; } else { m[0][0] *= x; m[0][1] *= x; @@ -775,8 +851,8 @@ void QMatrix4x4::scale(qreal x, qreal y) m[1][1] *= y; m[1][2] *= y; m[1][3] *= y; - flagBits = General; } + flagBits |= Scale; } /*! @@ -789,20 +865,20 @@ void QMatrix4x4::scale(qreal x, qreal y) */ void QMatrix4x4::scale(qreal x, qreal y, qreal z) { - if (flagBits == Identity) { + if (flagBits < Scale) { m[0][0] = x; m[1][1] = y; m[2][2] = z; - flagBits = Scale; - } else if (flagBits == Scale || flagBits == (Scale | Translation)) { + } else if (flagBits < Rotation2D) { m[0][0] *= x; m[1][1] *= y; m[2][2] *= z; - } else if (flagBits == Translation) { - m[0][0] = x; - m[1][1] = y; - m[2][2] = z; - flagBits |= Scale; + } else if (flagBits < Rotation) { + m[0][0] *= x; + m[0][1] *= x; + m[1][0] *= y; + m[1][1] *= y; + m[2][2] *= z; } else { m[0][0] *= x; m[0][1] *= x; @@ -816,8 +892,8 @@ void QMatrix4x4::scale(qreal x, qreal y, qreal z) m[2][1] *= z; m[2][2] *= z; m[2][3] *= z; - flagBits = General; } + flagBits |= Scale; } /*! @@ -830,20 +906,20 @@ void QMatrix4x4::scale(qreal x, qreal y, qreal z) */ void QMatrix4x4::scale(qreal factor) { - if (flagBits == Identity) { + if (flagBits < Scale) { m[0][0] = factor; m[1][1] = factor; m[2][2] = factor; - flagBits = Scale; - } else if (flagBits == Scale || flagBits == (Scale | Translation)) { + } else if (flagBits < Rotation2D) { m[0][0] *= factor; m[1][1] *= factor; m[2][2] *= factor; - } else if (flagBits == Translation) { - m[0][0] = factor; - m[1][1] = factor; - m[2][2] = factor; - flagBits |= Scale; + } else if (flagBits < Rotation) { + m[0][0] *= factor; + m[0][1] *= factor; + m[1][0] *= factor; + m[1][1] *= factor; + m[2][2] *= factor; } else { m[0][0] *= factor; m[0][1] *= factor; @@ -857,8 +933,8 @@ void QMatrix4x4::scale(qreal factor) m[2][1] *= factor; m[2][2] *= factor; m[2][3] *= factor; - flagBits = General; } + flagBits |= Scale; } #ifndef QT_NO_VECTOR3D @@ -868,6 +944,7 @@ void QMatrix4x4::scale(qreal factor) \sa scale(), rotate() */ + void QMatrix4x4::translate(const QVector3D& vector) { qreal vx = vector.x(); @@ -877,7 +954,6 @@ void QMatrix4x4::translate(const QVector3D& vector) m[3][0] = vx; m[3][1] = vy; m[3][2] = vz; - flagBits = Translation; } else if (flagBits == Translation) { m[3][0] += vx; m[3][1] += vy; @@ -886,23 +962,22 @@ void QMatrix4x4::translate(const QVector3D& vector) m[3][0] = m[0][0] * vx; m[3][1] = m[1][1] * vy; m[3][2] = m[2][2] * vz; - flagBits |= Translation; - } else if (flagBits == (Scale | Translation)) { + } else if (flagBits == (Translation | Scale)) { m[3][0] += m[0][0] * vx; m[3][1] += m[1][1] * vy; m[3][2] += m[2][2] * vz; + } else if (flagBits < Rotation) { + m[3][0] += m[0][0] * vx + m[1][0] * vy; + m[3][1] += m[0][1] * vx + m[1][1] * vy; + m[3][2] += m[2][2] * vz; } else { m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz; m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz; m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz; m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz; - if (flagBits == Rotation) - flagBits |= Translation; - else if (flagBits != (Rotation | Translation)) - flagBits = General; } + flagBits |= Translation; } - #endif /*! @@ -918,28 +993,25 @@ void QMatrix4x4::translate(qreal x, qreal y) if (flagBits == Identity) { m[3][0] = x; m[3][1] = y; - flagBits = Translation; } else if (flagBits == Translation) { m[3][0] += x; m[3][1] += y; } else if (flagBits == Scale) { m[3][0] = m[0][0] * x; m[3][1] = m[1][1] * y; - m[3][2] = 0.; - flagBits |= Translation; - } else if (flagBits == (Scale | Translation)) { + } else if (flagBits == (Translation | Scale)) { m[3][0] += m[0][0] * x; m[3][1] += m[1][1] * y; + } else if (flagBits < Rotation) { + m[3][0] += m[0][0] * x + m[1][0] * y; + m[3][1] += m[0][1] * x + m[1][1] * y; } else { m[3][0] += m[0][0] * x + m[1][0] * y; m[3][1] += m[0][1] * x + m[1][1] * y; m[3][2] += m[0][2] * x + m[1][2] * y; m[3][3] += m[0][3] * x + m[1][3] * y; - if (flagBits == Rotation) - flagBits |= Translation; - else if (flagBits != (Rotation | Translation)) - flagBits = General; } + flagBits |= Translation; } /*! @@ -956,7 +1028,6 @@ void QMatrix4x4::translate(qreal x, qreal y, qreal z) m[3][0] = x; m[3][1] = y; m[3][2] = z; - flagBits = Translation; } else if (flagBits == Translation) { m[3][0] += x; m[3][1] += y; @@ -965,31 +1036,31 @@ void QMatrix4x4::translate(qreal x, qreal y, qreal z) m[3][0] = m[0][0] * x; m[3][1] = m[1][1] * y; m[3][2] = m[2][2] * z; - flagBits |= Translation; - } else if (flagBits == (Scale | Translation)) { + } else if (flagBits == (Translation | Scale)) { m[3][0] += m[0][0] * x; m[3][1] += m[1][1] * y; m[3][2] += m[2][2] * z; + } else if (flagBits < Rotation) { + m[3][0] += m[0][0] * x + m[1][0] * y; + m[3][1] += m[0][1] * x + m[1][1] * y; + m[3][2] += m[2][2] * z; } else { m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z; m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z; m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z; m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z; - if (flagBits == Rotation) - flagBits |= Translation; - else if (flagBits != (Rotation | Translation)) - flagBits = General; } + flagBits |= Translation; } #ifndef QT_NO_VECTOR3D - /*! Multiples this matrix by another that rotates coordinates through \a angle degrees about \a vector. \sa scale(), translate() */ + void QMatrix4x4::rotate(qreal angle, const QVector3D& vector) { rotate(angle, vector.x(), vector.y(), vector.z()); @@ -1009,8 +1080,7 @@ void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) { if (angle == 0.0f) return; - QMatrix4x4 m(1); // The "1" says to not load the identity. - qreal c, s, ic; + qreal c, s; if (angle == 90.0f || angle == -270.0f) { s = 1.0f; c = 0.0f; @@ -1025,86 +1095,87 @@ void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) c = qCos(a); s = qSin(a); } - bool quick = false; if (x == 0.0f) { if (y == 0.0f) { if (z != 0.0f) { // Rotate around the Z axis. - m.setToIdentity(); - m.m[0][0] = c; - m.m[1][1] = c; - if (z < 0.0f) { - m.m[1][0] = s; - m.m[0][1] = -s; - } else { - m.m[1][0] = -s; - m.m[0][1] = s; - } - m.flagBits = General; - quick = true; + if (z < 0) + s = -s; + qreal tmp; + m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s; + m[1][0] = m[1][0] * c - tmp * s; + m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s; + m[1][1] = m[1][1] * c - tmp * s; + m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s; + m[1][2] = m[1][2] * c - tmp * s; + m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; + m[1][3] = m[1][3] * c - tmp * s; + + flagBits |= Rotation2D; + return; } } else if (z == 0.0f) { // Rotate around the Y axis. - m.setToIdentity(); - m.m[0][0] = c; - m.m[2][2] = c; - if (y < 0.0f) { - m.m[2][0] = -s; - m.m[0][2] = s; - } else { - m.m[2][0] = s; - m.m[0][2] = -s; - } - m.flagBits = General; - quick = true; + if (y < 0) + s = -s; + qreal tmp; + m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s; + m[0][0] = m[0][0] * c - tmp * s; + m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s; + m[0][1] = m[0][1] * c - tmp * s; + m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s; + m[0][2] = m[0][2] * c - tmp * s; + m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s; + m[0][3] = m[0][3] * c - tmp * s; + + flagBits |= Rotation; + return; } } else if (y == 0.0f && z == 0.0f) { // Rotate around the X axis. - m.setToIdentity(); - m.m[1][1] = c; - m.m[2][2] = c; - if (x < 0.0f) { - m.m[2][1] = s; - m.m[1][2] = -s; - } else { - m.m[2][1] = -s; - m.m[1][2] = s; - } - m.flagBits = General; - quick = true; + if (x < 0) + s = -s; + qreal tmp; + m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s; + m[2][0] = m[2][0] * c - tmp * s; + m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s; + m[2][1] = m[2][1] * c - tmp * s; + m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s; + m[2][2] = m[2][2] * c - tmp * s; + m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s; + m[2][3] = m[2][3] * c - tmp * s; + + flagBits |= Rotation; + return; } - if (!quick) { - qreal len = x * x + y * y + z * z; - if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) { - len = qSqrt(len); - x /= len; - y /= len; - z /= len; - } - ic = 1.0f - c; - m.m[0][0] = x * x * ic + c; - m.m[1][0] = x * y * ic - z * s; - m.m[2][0] = x * z * ic + y * s; - m.m[3][0] = 0.0f; - m.m[0][1] = y * x * ic + z * s; - m.m[1][1] = y * y * ic + c; - m.m[2][1] = y * z * ic - x * s; - m.m[3][1] = 0.0f; - m.m[0][2] = x * z * ic - y * s; - m.m[1][2] = y * z * ic + x * s; - m.m[2][2] = z * z * ic + c; - m.m[3][2] = 0.0f; - m.m[0][3] = 0.0f; - m.m[1][3] = 0.0f; - m.m[2][3] = 0.0f; - m.m[3][3] = 1.0f; + + qreal len = x * x + y * y + z * z; + if (!qFuzzyCompare(len, qreal(1)) && !qFuzzyIsNull(len)) { + len = qSqrt(len); + x /= len; + y /= len; + z /= len; } - int flags = flagBits; - *this *= m; - if (flags != Identity) - flagBits = flags | Rotation; - else - flagBits = Rotation; + qreal ic = 1.0f - c; + QMatrix4x4 rot(1); // The "1" says to not load the identity. + rot.m[0][0] = x * x * ic + c; + rot.m[1][0] = x * y * ic - z * s; + rot.m[2][0] = x * z * ic + y * s; + rot.m[3][0] = 0.0f; + rot.m[0][1] = y * x * ic + z * s; + rot.m[1][1] = y * y * ic + c; + rot.m[2][1] = y * z * ic - x * s; + rot.m[3][1] = 0.0f; + rot.m[0][2] = x * z * ic - y * s; + rot.m[1][2] = y * z * ic + x * s; + rot.m[2][2] = z * z * ic + c; + rot.m[3][2] = 0.0f; + rot.m[0][3] = 0.0f; + rot.m[1][3] = 0.0f; + rot.m[2][3] = 0.0f; + rot.m[3][3] = 1.0f; + rot.flagBits = Rotation; + *this *= rot; } /*! @@ -1116,8 +1187,7 @@ void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z) // and projection back to 2D in a single step. if (angle == 0.0f) return; - QMatrix4x4 m(1); // The "1" says to not load the identity. - qreal c, s, ic; + qreal c, s; if (angle == 90.0f || angle == -270.0f) { s = 1.0f; c = 0.0f; @@ -1132,82 +1202,74 @@ void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z) c = qCos(a); s = qSin(a); } - bool quick = false; if (x == 0.0f) { if (y == 0.0f) { if (z != 0.0f) { // Rotate around the Z axis. - m.setToIdentity(); - m.m[0][0] = c; - m.m[1][1] = c; - if (z < 0.0f) { - m.m[1][0] = s; - m.m[0][1] = -s; - } else { - m.m[1][0] = -s; - m.m[0][1] = s; - } - m.flagBits = General; - quick = true; + if (z < 0) + s = -s; + qreal tmp; + m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s; + m[1][0] = m[1][0] * c - tmp * s; + m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s; + m[1][1] = m[1][1] * c - tmp * s; + m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s; + m[1][2] = m[1][2] * c - tmp * s; + m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; + m[1][3] = m[1][3] * c - tmp * s; + + flagBits |= Rotation2D; + return; } } else if (z == 0.0f) { // Rotate around the Y axis. - m.setToIdentity(); - m.m[0][0] = c; - m.m[2][2] = 1.0f; - if (y < 0.0f) { - m.m[0][3] = -s * inv_dist_to_plane; - } else { - m.m[0][3] = s * inv_dist_to_plane; - } - m.flagBits = General; - quick = true; + if (y < 0) + s = -s; + m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane; + m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane; + m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane; + m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane; + flagBits = General; + return; } } else if (y == 0.0f && z == 0.0f) { // Rotate around the X axis. - m.setToIdentity(); - m.m[1][1] = c; - m.m[2][2] = 1.0f; - if (x < 0.0f) { - m.m[1][3] = s * inv_dist_to_plane; - } else { - m.m[1][3] = -s * inv_dist_to_plane; - } - m.flagBits = General; - quick = true; + if (x < 0) + s = -s; + m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane; + m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane; + m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane; + m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane; + flagBits = General; + return; } - if (!quick) { - qreal len = x * x + y * y + z * z; - if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) { - len = qSqrt(len); - x /= len; - y /= len; - z /= len; - } - ic = 1.0f - c; - m.m[0][0] = x * x * ic + c; - m.m[1][0] = x * y * ic - z * s; - m.m[2][0] = 0.0f; - m.m[3][0] = 0.0f; - m.m[0][1] = y * x * ic + z * s; - m.m[1][1] = y * y * ic + c; - m.m[2][1] = 0.0f; - m.m[3][1] = 0.0f; - m.m[0][2] = 0.0f; - m.m[1][2] = 0.0f; - m.m[2][2] = 1.0f; - m.m[3][2] = 0.0f; - m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane; - m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane; - m.m[2][3] = 0.0f; - m.m[3][3] = 1.0f; + qreal len = x * x + y * y + z * z; + if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) { + len = qSqrt(len); + x /= len; + y /= len; + z /= len; } - int flags = flagBits; - *this *= m; - if (flags != Identity) - flagBits = flags | Rotation; - else - flagBits = Rotation; + qreal ic = 1.0f - c; + QMatrix4x4 rot(1); // The "1" says to not load the identity. + rot.m[0][0] = x * x * ic + c; + rot.m[1][0] = x * y * ic - z * s; + rot.m[2][0] = 0.0f; + rot.m[3][0] = 0.0f; + rot.m[0][1] = y * x * ic + z * s; + rot.m[1][1] = y * y * ic + c; + rot.m[2][1] = 0.0f; + rot.m[3][1] = 0.0f; + rot.m[0][2] = 0.0f; + rot.m[1][2] = 0.0f; + rot.m[2][2] = 1.0f; + rot.m[3][2] = 0.0f; + rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane; + rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane; + rot.m[2][3] = 0.0f; + rot.m[3][3] = 1.0f; + rot.flagBits = General; + *this *= rot; } #ifndef QT_NO_QUATERNION @@ -1249,12 +1311,8 @@ void QMatrix4x4::rotate(const QQuaternion& quaternion) m.m[1][3] = 0.0f; m.m[2][3] = 0.0f; m.m[3][3] = 1.0f; - int flags = flagBits; + m.flagBits = Rotation; *this *= m; - if (flags != Identity) - flagBits = flags | Rotation; - else - flagBits = Rotation; } #endif @@ -1309,22 +1367,6 @@ void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal n qreal width = right - left; qreal invheight = top - bottom; qreal clip = farPlane - nearPlane; -#ifndef QT_NO_VECTOR3D - if (clip == 2.0f && (nearPlane + farPlane) == 0.0f) { - // We can express this projection as a translate and scale - // which will be more efficient to modify with further - // transformations than producing a "General" matrix. - translate(QVector3D - (-(left + right) / width, - -(top + bottom) / invheight, - 0.0f)); - scale(QVector3D - (2.0f / width, - 2.0f / invheight, - -1.0f)); - return; - } -#endif QMatrix4x4 m(1); m.m[0][0] = 2.0f / width; m.m[1][0] = 0.0f; @@ -1342,10 +1384,10 @@ void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal n m.m[1][3] = 0.0f; m.m[2][3] = 0.0f; m.m[3][3] = 1.0f; + m.flagBits = Translation | Scale; // Apply the projection. *this *= m; - return; } /*! @@ -1383,6 +1425,7 @@ void QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal m.m[1][3] = 0.0f; m.m[2][3] = -1.0f; m.m[3][3] = 0.0f; + m.flagBits = General; // Apply the projection. *this *= m; @@ -1426,6 +1469,7 @@ void QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal f m.m[1][3] = 0.0f; m.m[2][3] = -1.0f; m.m[3][3] = 0.0f; + m.flagBits = General; // Apply the projection. *this *= m; @@ -1446,7 +1490,6 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe QVector3D upVector = QVector3D::crossProduct(side, forward); QMatrix4x4 m(1); - m.m[0][0] = side.x(); m.m[1][0] = side.y(); m.m[2][0] = side.z(); @@ -1463,6 +1506,7 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe m.m[1][3] = 0.0f; m.m[2][3] = 0.0f; m.m[3][3] = 1.0f; + m.flagBits = Rotation; *this *= m; translate(-eye); @@ -1471,6 +1515,8 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe #endif /*! + \deprecated + Flips between right-handed and left-handed coordinate systems by multiplying the y and z co-ordinates by -1. This is normally used to create a left-handed orthographic view without scaling @@ -1480,17 +1526,13 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe */ void QMatrix4x4::flipCoordinates() { - if (flagBits == Scale || flagBits == (Scale | Translation)) { + // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and + // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so + // I'm deprecating this function. + if (flagBits < Rotation2D) { + // Translation | Scale m[1][1] = -m[1][1]; m[2][2] = -m[2][2]; - } else if (flagBits == Translation) { - m[1][1] = -m[1][1]; - m[2][2] = -m[2][2]; - flagBits |= Scale; - } else if (flagBits == Identity) { - m[1][1] = -1.0f; - m[2][2] = -1.0f; - flagBits = Scale; } else { m[1][0] = -m[1][0]; m[1][1] = -m[1][1]; @@ -1500,8 +1542,8 @@ void QMatrix4x4::flipCoordinates() m[2][1] = -m[2][1]; m[2][2] = -m[2][2]; m[2][3] = -m[2][3]; - flagBits = General; } + flagBits |= Scale; } /*! @@ -1568,12 +1610,9 @@ QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const { if (distanceToPlane == 1024.0f) { // Optimize the common case with constants. - return QTransform(m[0][0], m[0][1], - m[0][3] - m[0][2] * inv_dist_to_plane, - m[1][0], m[1][1], - m[1][3] - m[1][2] * inv_dist_to_plane, - m[3][0], m[3][1], - m[3][3] - m[3][2] * inv_dist_to_plane); + return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * inv_dist_to_plane, + m[1][0], m[1][1], m[1][3] - m[1][2] * inv_dist_to_plane, + m[3][0], m[3][1], m[3][3] - m[3][2] * inv_dist_to_plane); } else if (distanceToPlane != 0.0f) { // The following projection matrix is pre-multiplied with "matrix": // | 1 0 0 0 | @@ -1654,7 +1693,13 @@ QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const */ QRect QMatrix4x4::mapRect(const QRect& rect) const { - if (flagBits == (Translation | Scale) || flagBits == Scale) { + if (flagBits < Scale) { + // Translation + return QRect(qRound(rect.x() + m[3][0]), + qRound(rect.y() + m[3][1]), + rect.width(), rect.height()); + } else if (flagBits < Rotation2D) { + // Translation | Scale qreal x = rect.x() * m[0][0] + m[3][0]; qreal y = rect.y() * m[1][1] + m[3][1]; qreal w = rect.width() * m[0][0]; @@ -1668,10 +1713,6 @@ QRect QMatrix4x4::mapRect(const QRect& rect) const y -= h; } return QRect(qRound(x), qRound(y), qRound(w), qRound(h)); - } else if (flagBits == Translation) { - return QRect(qRound(rect.x() + m[3][0]), - qRound(rect.y() + m[3][1]), - rect.width(), rect.height()); } QPoint tl = map(rect.topLeft()); @@ -1698,7 +1739,11 @@ QRect QMatrix4x4::mapRect(const QRect& rect) const */ QRectF QMatrix4x4::mapRect(const QRectF& rect) const { - if (flagBits == (Translation | Scale) || flagBits == Scale) { + if (flagBits < Scale) { + // Translation + return rect.translated(m[3][0], m[3][1]); + } else if (flagBits < Rotation2D) { + // Translation | Scale qreal x = rect.x() * m[0][0] + m[3][0]; qreal y = rect.y() * m[1][1] + m[3][1]; qreal w = rect.width() * m[0][0]; @@ -1712,8 +1757,6 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const y -= h; } return QRectF(x, y, w, h); - } else if (flagBits == Translation) { - return rect.translated(m[3][0], m[3][1]); } QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight()); @@ -1780,6 +1823,8 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const result.m[3][2] = -(result.m[0][2] * m[3][0] + result.m[1][2] * m[3][1] + result.m[2][2] * m[3][2]); result.m[3][3] = 1.0f; + result.flagBits = flagBits; + return result; } @@ -1805,40 +1850,50 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const */ void QMatrix4x4::optimize() { - // If the last element is not 1, then it can never be special. - if (m[3][3] != 1.0f) { - flagBits = General; + // If the last row is not (0, 0, 0, 1), the matrix is not a special type. + flagBits = General; + if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1) return; - } - // If the upper three elements m12, m13, and m21 are not all zero, - // or the lower elements below the diagonal are not all zero, then - // the matrix can never be special. - if (m[1][0] != 0.0f || m[2][0] != 0.0f || m[2][1] != 0.0f) { - flagBits = General; - return; - } - if (m[0][1] != 0.0f || m[0][2] != 0.0f || m[0][3] != 0.0f || - m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][3] != 0.0f) { - flagBits = General; - return; - } + flagBits &= ~Perspective; - // Determine what we have in the remaining regions of the matrix. - bool identityAlongDiagonal - = (m[0][0] == 1.0f && m[1][1] == 1.0f && m[2][2] == 1.0f); - bool translationPresent - = (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f); + // If the last column is (0, 0, 0, 1), then there is no translation. + if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0) + flagBits &= ~Translation; - // Now determine the special matrix type. - if (translationPresent && identityAlongDiagonal) - flagBits = Translation; - else if (translationPresent) - flagBits = (Translation | Scale); - else if (identityAlongDiagonal) - flagBits = Identity; - else - flagBits = Scale; + // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z. + if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) { + flagBits &= ~Rotation; + // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation. + if (!m[0][1] && !m[1][0]) { + flagBits &= ~Rotation2D; + // Check for identity. + if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1) + flagBits &= ~Scale; + } else { + // If the columns are orthonormal and form a right-handed system, then there is no scale. + qreal det = matrixDet2(m, 0, 1, 0, 1); + qreal lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1]; + qreal lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1]; + qreal lenZ = m[2][2]; + if (qFuzzyCompare(det, qreal(1)) && qFuzzyCompare(lenX, qreal(1)) + && qFuzzyCompare(lenY, qreal(1)) && qFuzzyCompare(lenZ, qreal(1))) + { + flagBits &= ~Scale; + } + } + } else { + // If the columns are orthonormal and form a right-handed system, then there is no scale. + qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2); + qreal lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2]; + qreal lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1] + m[1][2] * m[1][2]; + qreal lenZ = m[2][0] * m[2][0] + m[2][1] * m[2][1] + m[2][2] * m[2][2]; + if (qFuzzyCompare(det, qreal(1)) && qFuzzyCompare(lenX, qreal(1)) + && qFuzzyCompare(lenY, qreal(1)) && qFuzzyCompare(lenZ, qreal(1))) + { + flagBits &= ~Scale; + } + } } /*! @@ -1855,18 +1910,24 @@ QDebug operator<<(QDebug dbg, const QMatrix4x4 &m) { // Create a string that represents the matrix type. QByteArray bits; - if ((m.flagBits & QMatrix4x4::Identity) != 0) - bits += "Identity,"; - if ((m.flagBits & QMatrix4x4::General) != 0) - bits += "General,"; - if ((m.flagBits & QMatrix4x4::Translation) != 0) - bits += "Translation,"; - if ((m.flagBits & QMatrix4x4::Scale) != 0) - bits += "Scale,"; - if ((m.flagBits & QMatrix4x4::Rotation) != 0) - bits += "Rotation,"; - if (bits.size() > 0) - bits = bits.left(bits.size() - 1); + if (m.flagBits == QMatrix4x4::Identity) { + bits = "Identity"; + } else if (m.flagBits == QMatrix4x4::General) { + bits = "General"; + } else { + if ((m.flagBits & QMatrix4x4::Translation) != 0) + bits += "Translation,"; + if ((m.flagBits & QMatrix4x4::Scale) != 0) + bits += "Scale,"; + if ((m.flagBits & QMatrix4x4::Rotation2D) != 0) + bits += "Rotation2D,"; + if ((m.flagBits & QMatrix4x4::Rotation) != 0) + bits += "Rotation,"; + if ((m.flagBits & QMatrix4x4::Perspective) != 0) + bits += "Perspective,"; + if (bits.size() > 0) + bits = bits.left(bits.size() - 1); + } // Output in row-major order because it is more human-readable. dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << endl diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index bfbe4b97934..2c98dd03e30 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -80,11 +80,13 @@ public: inline const qreal& operator()(int row, int column) const; inline qreal& operator()(int row, int column); +#ifndef QT_NO_VECTOR4D inline QVector4D column(int index) const; inline void setColumn(int index, const QVector4D& value); inline QVector4D row(int index) const; inline void setRow(int index, const QVector4D& value); +#endif inline bool isIdentity() const; inline void setToIdentity(); @@ -188,16 +190,19 @@ private: qreal m[4][4]; // Column-major order to match OpenGL. int flagBits; // Flag bits from the enum below. + // When matrices are multiplied, the flag bits are or-ed together. enum { - Identity = 0x0001, // Identity matrix - General = 0x0002, // General matrix, unknown contents - Translation = 0x0004, // Contains a simple translation - Scale = 0x0008, // Contains a simple scale - Rotation = 0x0010 // Contains a simple rotation + Identity = 0x0000, // Identity matrix + Translation = 0x0001, // Contains a translation + Scale = 0x0002, // Contains a scale + Rotation2D = 0x0004, // Contains a rotation about the Z axis + Rotation = 0x0008, // Contains an arbitrary rotation + Perspective = 0x0010, // Last row is different from (0, 0, 0, 1) + General = 0x001f // General matrix, unknown contents }; // Construct without initializing identity matrix. - QMatrix4x4(int) { flagBits = General; } + QMatrix4x4(int) { } QMatrix4x4 orthonormalInverse() const; @@ -270,6 +275,7 @@ inline qreal& QMatrix4x4::operator()(int aRow, int aColumn) return m[aColumn][aRow]; } +#ifndef QT_NO_VECTOR4D inline QVector4D QMatrix4x4::column(int index) const { Q_ASSERT(index >= 0 && index < 4); @@ -301,6 +307,7 @@ inline void QMatrix4x4::setRow(int index, const QVector4D& value) m[3][index] = value.w(); flagBits = General; } +#endif Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor); @@ -409,15 +416,100 @@ inline QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other) inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other) { - if (flagBits == Identity) { - *this = other; - return *this; - } else if (other.flagBits == Identity) { - return *this; - } else { - *this = *this * other; + flagBits |= other.flagBits; + + if (flagBits < Rotation2D) { + m[3][0] += m[0][0] * other.m[3][0]; + m[3][1] += m[1][1] * other.m[3][1]; + m[3][2] += m[2][2] * other.m[3][2]; + + m[0][0] *= other.m[0][0]; + m[1][1] *= other.m[1][1]; + m[2][2] *= other.m[2][2]; return *this; } + + qreal m0, m1, m2; + m0 = m[0][0] * other.m[0][0] + + m[1][0] * other.m[0][1] + + m[2][0] * other.m[0][2] + + m[3][0] * other.m[0][3]; + m1 = m[0][0] * other.m[1][0] + + m[1][0] * other.m[1][1] + + m[2][0] * other.m[1][2] + + m[3][0] * other.m[1][3]; + m2 = m[0][0] * other.m[2][0] + + m[1][0] * other.m[2][1] + + m[2][0] * other.m[2][2] + + m[3][0] * other.m[2][3]; + m[3][0] = m[0][0] * other.m[3][0] + + m[1][0] * other.m[3][1] + + m[2][0] * other.m[3][2] + + m[3][0] * other.m[3][3]; + m[0][0] = m0; + m[1][0] = m1; + m[2][0] = m2; + + m0 = m[0][1] * other.m[0][0] + + m[1][1] * other.m[0][1] + + m[2][1] * other.m[0][2] + + m[3][1] * other.m[0][3]; + m1 = m[0][1] * other.m[1][0] + + m[1][1] * other.m[1][1] + + m[2][1] * other.m[1][2] + + m[3][1] * other.m[1][3]; + m2 = m[0][1] * other.m[2][0] + + m[1][1] * other.m[2][1] + + m[2][1] * other.m[2][2] + + m[3][1] * other.m[2][3]; + m[3][1] = m[0][1] * other.m[3][0] + + m[1][1] * other.m[3][1] + + m[2][1] * other.m[3][2] + + m[3][1] * other.m[3][3]; + m[0][1] = m0; + m[1][1] = m1; + m[2][1] = m2; + + m0 = m[0][2] * other.m[0][0] + + m[1][2] * other.m[0][1] + + m[2][2] * other.m[0][2] + + m[3][2] * other.m[0][3]; + m1 = m[0][2] * other.m[1][0] + + m[1][2] * other.m[1][1] + + m[2][2] * other.m[1][2] + + m[3][2] * other.m[1][3]; + m2 = m[0][2] * other.m[2][0] + + m[1][2] * other.m[2][1] + + m[2][2] * other.m[2][2] + + m[3][2] * other.m[2][3]; + m[3][2] = m[0][2] * other.m[3][0] + + m[1][2] * other.m[3][1] + + m[2][2] * other.m[3][2] + + m[3][2] * other.m[3][3]; + m[0][2] = m0; + m[1][2] = m1; + m[2][2] = m2; + + m0 = m[0][3] * other.m[0][0] + + m[1][3] * other.m[0][1] + + m[2][3] * other.m[0][2] + + m[3][3] * other.m[0][3]; + m1 = m[0][3] * other.m[1][0] + + m[1][3] * other.m[1][1] + + m[2][3] * other.m[1][2] + + m[3][3] * other.m[1][3]; + m2 = m[0][3] * other.m[2][0] + + m[1][3] * other.m[2][1] + + m[2][3] * other.m[2][2] + + m[3][3] * other.m[2][3]; + m[3][3] = m[0][3] * other.m[3][0] + + m[1][3] * other.m[3][1] + + m[2][3] * other.m[3][2] + + m[3][3] * other.m[3][3]; + m[0][3] = m0; + m[1][3] = m1; + m[2][3] = m2; + return *this; } inline QMatrix4x4& QMatrix4x4::operator*=(qreal factor) @@ -501,6 +593,7 @@ inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2) m.m[3][1] = m1.m[3][1] + m2.m[3][1]; m.m[3][2] = m1.m[3][2] + m2.m[3][2]; m.m[3][3] = m1.m[3][3] + m2.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } @@ -523,81 +616,95 @@ inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2) m.m[3][1] = m1.m[3][1] - m2.m[3][1]; m.m[3][2] = m1.m[3][2] - m2.m[3][2]; m.m[3][3] = m1.m[3][3] - m2.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2) { - if (m1.flagBits == QMatrix4x4::Identity) - return m2; - else if (m2.flagBits == QMatrix4x4::Identity) - return m1; + int flagBits = m1.flagBits | m2.flagBits; + if (flagBits < QMatrix4x4::Rotation2D) { + QMatrix4x4 m = m1; + m.m[3][0] += m.m[0][0] * m2.m[3][0]; + m.m[3][1] += m.m[1][1] * m2.m[3][1]; + m.m[3][2] += m.m[2][2] * m2.m[3][2]; + + m.m[0][0] *= m2.m[0][0]; + m.m[1][1] *= m2.m[1][1]; + m.m[2][2] *= m2.m[2][2]; + m.flagBits = flagBits; + return m; + } QMatrix4x4 m(1); - m.m[0][0] = m1.m[0][0] * m2.m[0][0] + - m1.m[1][0] * m2.m[0][1] + - m1.m[2][0] * m2.m[0][2] + - m1.m[3][0] * m2.m[0][3]; - m.m[0][1] = m1.m[0][1] * m2.m[0][0] + - m1.m[1][1] * m2.m[0][1] + - m1.m[2][1] * m2.m[0][2] + - m1.m[3][1] * m2.m[0][3]; - m.m[0][2] = m1.m[0][2] * m2.m[0][0] + - m1.m[1][2] * m2.m[0][1] + - m1.m[2][2] * m2.m[0][2] + - m1.m[3][2] * m2.m[0][3]; - m.m[0][3] = m1.m[0][3] * m2.m[0][0] + - m1.m[1][3] * m2.m[0][1] + - m1.m[2][3] * m2.m[0][2] + - m1.m[3][3] * m2.m[0][3]; - m.m[1][0] = m1.m[0][0] * m2.m[1][0] + - m1.m[1][0] * m2.m[1][1] + - m1.m[2][0] * m2.m[1][2] + - m1.m[3][0] * m2.m[1][3]; - m.m[1][1] = m1.m[0][1] * m2.m[1][0] + - m1.m[1][1] * m2.m[1][1] + - m1.m[2][1] * m2.m[1][2] + - m1.m[3][1] * m2.m[1][3]; - m.m[1][2] = m1.m[0][2] * m2.m[1][0] + - m1.m[1][2] * m2.m[1][1] + - m1.m[2][2] * m2.m[1][2] + - m1.m[3][2] * m2.m[1][3]; - m.m[1][3] = m1.m[0][3] * m2.m[1][0] + - m1.m[1][3] * m2.m[1][1] + - m1.m[2][3] * m2.m[1][2] + - m1.m[3][3] * m2.m[1][3]; - m.m[2][0] = m1.m[0][0] * m2.m[2][0] + - m1.m[1][0] * m2.m[2][1] + - m1.m[2][0] * m2.m[2][2] + - m1.m[3][0] * m2.m[2][3]; - m.m[2][1] = m1.m[0][1] * m2.m[2][0] + - m1.m[1][1] * m2.m[2][1] + - m1.m[2][1] * m2.m[2][2] + - m1.m[3][1] * m2.m[2][3]; - m.m[2][2] = m1.m[0][2] * m2.m[2][0] + - m1.m[1][2] * m2.m[2][1] + - m1.m[2][2] * m2.m[2][2] + - m1.m[3][2] * m2.m[2][3]; - m.m[2][3] = m1.m[0][3] * m2.m[2][0] + - m1.m[1][3] * m2.m[2][1] + - m1.m[2][3] * m2.m[2][2] + - m1.m[3][3] * m2.m[2][3]; - m.m[3][0] = m1.m[0][0] * m2.m[3][0] + - m1.m[1][0] * m2.m[3][1] + - m1.m[2][0] * m2.m[3][2] + - m1.m[3][0] * m2.m[3][3]; - m.m[3][1] = m1.m[0][1] * m2.m[3][0] + - m1.m[1][1] * m2.m[3][1] + - m1.m[2][1] * m2.m[3][2] + - m1.m[3][1] * m2.m[3][3]; - m.m[3][2] = m1.m[0][2] * m2.m[3][0] + - m1.m[1][2] * m2.m[3][1] + - m1.m[2][2] * m2.m[3][2] + - m1.m[3][2] * m2.m[3][3]; - m.m[3][3] = m1.m[0][3] * m2.m[3][0] + - m1.m[1][3] * m2.m[3][1] + - m1.m[2][3] * m2.m[3][2] + - m1.m[3][3] * m2.m[3][3]; + m.m[0][0] = m1.m[0][0] * m2.m[0][0] + + m1.m[1][0] * m2.m[0][1] + + m1.m[2][0] * m2.m[0][2] + + m1.m[3][0] * m2.m[0][3]; + m.m[0][1] = m1.m[0][1] * m2.m[0][0] + + m1.m[1][1] * m2.m[0][1] + + m1.m[2][1] * m2.m[0][2] + + m1.m[3][1] * m2.m[0][3]; + m.m[0][2] = m1.m[0][2] * m2.m[0][0] + + m1.m[1][2] * m2.m[0][1] + + m1.m[2][2] * m2.m[0][2] + + m1.m[3][2] * m2.m[0][3]; + m.m[0][3] = m1.m[0][3] * m2.m[0][0] + + m1.m[1][3] * m2.m[0][1] + + m1.m[2][3] * m2.m[0][2] + + m1.m[3][3] * m2.m[0][3]; + + m.m[1][0] = m1.m[0][0] * m2.m[1][0] + + m1.m[1][0] * m2.m[1][1] + + m1.m[2][0] * m2.m[1][2] + + m1.m[3][0] * m2.m[1][3]; + m.m[1][1] = m1.m[0][1] * m2.m[1][0] + + m1.m[1][1] * m2.m[1][1] + + m1.m[2][1] * m2.m[1][2] + + m1.m[3][1] * m2.m[1][3]; + m.m[1][2] = m1.m[0][2] * m2.m[1][0] + + m1.m[1][2] * m2.m[1][1] + + m1.m[2][2] * m2.m[1][2] + + m1.m[3][2] * m2.m[1][3]; + m.m[1][3] = m1.m[0][3] * m2.m[1][0] + + m1.m[1][3] * m2.m[1][1] + + m1.m[2][3] * m2.m[1][2] + + m1.m[3][3] * m2.m[1][3]; + + m.m[2][0] = m1.m[0][0] * m2.m[2][0] + + m1.m[1][0] * m2.m[2][1] + + m1.m[2][0] * m2.m[2][2] + + m1.m[3][0] * m2.m[2][3]; + m.m[2][1] = m1.m[0][1] * m2.m[2][0] + + m1.m[1][1] * m2.m[2][1] + + m1.m[2][1] * m2.m[2][2] + + m1.m[3][1] * m2.m[2][3]; + m.m[2][2] = m1.m[0][2] * m2.m[2][0] + + m1.m[1][2] * m2.m[2][1] + + m1.m[2][2] * m2.m[2][2] + + m1.m[3][2] * m2.m[2][3]; + m.m[2][3] = m1.m[0][3] * m2.m[2][0] + + m1.m[1][3] * m2.m[2][1] + + m1.m[2][3] * m2.m[2][2] + + m1.m[3][3] * m2.m[2][3]; + + m.m[3][0] = m1.m[0][0] * m2.m[3][0] + + m1.m[1][0] * m2.m[3][1] + + m1.m[2][0] * m2.m[3][2] + + m1.m[3][0] * m2.m[3][3]; + m.m[3][1] = m1.m[0][1] * m2.m[3][0] + + m1.m[1][1] * m2.m[3][1] + + m1.m[2][1] * m2.m[3][2] + + m1.m[3][1] * m2.m[3][3]; + m.m[3][2] = m1.m[0][2] * m2.m[3][0] + + m1.m[1][2] * m2.m[3][1] + + m1.m[2][2] * m2.m[3][2] + + m1.m[3][2] * m2.m[3][3]; + m.m[3][3] = m1.m[0][3] * m2.m[3][0] + + m1.m[1][3] * m2.m[3][1] + + m1.m[2][3] * m2.m[3][2] + + m1.m[3][3] * m2.m[3][3]; + m.flagBits = flagBits; return m; } @@ -633,19 +740,16 @@ inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector) qreal x, y, z, w; if (matrix.flagBits == QMatrix4x4::Identity) { return vector; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QVector3D(vector.x() + matrix.m[3][0], - vector.y() + matrix.m[3][1], - vector.z() + matrix.m[3][2]); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QVector3D(vector.x() * matrix.m[0][0] + matrix.m[3][0], vector.y() * matrix.m[1][1] + matrix.m[3][1], vector.z() * matrix.m[2][2] + matrix.m[3][2]); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QVector3D(vector.x() * matrix.m[0][0], - vector.y() * matrix.m[1][1], - vector.z() * matrix.m[2][2]); + } else if (matrix.flagBits < QMatrix4x4::Rotation) { + // Translation | Scale | Rotation2D + return QVector3D(vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + matrix.m[3][0], + vector.x() * matrix.m[0][1] + vector.y() * matrix.m[1][1] + matrix.m[3][1], + vector.z() * matrix.m[2][2] + matrix.m[3][2]); } else { x = vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + @@ -771,16 +875,13 @@ inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point) yin = point.y(); if (matrix.flagBits == QMatrix4x4::Identity) { return point; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QPoint(qRound(xin + matrix.m[3][0]), - qRound(yin + matrix.m[3][1])); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]), qRound(yin * matrix.m[1][1] + matrix.m[3][1])); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QPoint(qRound(xin * matrix.m[0][0]), - qRound(yin * matrix.m[1][1])); + } else if (matrix.flagBits < QMatrix4x4::Perspective) { + return QPoint(qRound(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0]), + qRound(xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1])); } else { x = xin * matrix.m[0][0] + yin * matrix.m[1][0] + @@ -806,16 +907,13 @@ inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point) yin = point.y(); if (matrix.flagBits == QMatrix4x4::Identity) { return point; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QPointF(xin + matrix.m[3][0], - yin + matrix.m[3][1]); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QPointF(xin * matrix.m[0][0] + matrix.m[3][0], yin * matrix.m[1][1] + matrix.m[3][1]); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QPointF(xin * matrix.m[0][0], - yin * matrix.m[1][1]); + } else if (matrix.flagBits < QMatrix4x4::Perspective) { + return QPointF(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0], + xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1]); } else { x = xin * matrix.m[0][0] + yin * matrix.m[1][0] + @@ -853,6 +951,7 @@ inline QMatrix4x4 operator-(const QMatrix4x4& matrix) m.m[3][1] = -matrix.m[3][1]; m.m[3][2] = -matrix.m[3][2]; m.m[3][3] = -matrix.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } @@ -875,6 +974,7 @@ inline QMatrix4x4 operator*(qreal factor, const QMatrix4x4& matrix) m.m[3][1] = matrix.m[3][1] * factor; m.m[3][2] = matrix.m[3][2] * factor; m.m[3][3] = matrix.m[3][3] * factor; + m.flagBits = QMatrix4x4::General; return m; } @@ -897,6 +997,7 @@ inline QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor) m.m[3][1] = matrix.m[3][1] * factor; m.m[3][2] = matrix.m[3][2] * factor; m.m[3][3] = matrix.m[3][3] * factor; + m.flagBits = QMatrix4x4::General; return m; } @@ -939,9 +1040,11 @@ inline QVector3D QMatrix4x4::map(const QVector3D& point) const inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const { - if (flagBits == Identity || flagBits == Translation) { + if (flagBits < Scale) { + // Translation return vector; - } else if (flagBits == Scale || flagBits == (Translation | Scale)) { + } else if (flagBits < Rotation2D) { + // Translation | Scale return QVector3D(vector.x() * m[0][0], vector.y() * m[1][1], vector.z() * m[2][2]); diff --git a/src/modules/qt_v8.pri b/src/modules/qt_v8.pri new file mode 100644 index 00000000000..89d6c263e86 --- /dev/null +++ b/src/modules/qt_v8.pri @@ -0,0 +1,16 @@ +QT.v8.VERSION = 5.0.0 +QT.v8.MAJOR_VERSION = 5 +QT.v8.MINOR_VERSION = 0 +QT.v8.PATCH_VERSION = 0 + +QT.v8.name = QtV8 +QT.v8.bins = $$QT_MODULE_BIN_BASE +QT.v8.includes = $$QT_MODULE_INCLUDE_BASE/QtV8 +QT.v8.private_includes = $$QT_MODULE_INCLUDE_BASE/QtV8/$$QT.v8.VERSION +QT.v8.sources = $$QT_MODULE_BASE/src/v8 +QT.v8.libs = $$QT_MODULE_LIB_BASE +QT.v8.plugins = $$QT_MODULE_PLUGIN_BASE +QT.v8.imports = $$QT_MODULE_IMPORT_BASE +QT.v8.depends = +QT.v8.DEFINES = +!contains(QT_CONFIG, static): QT.v8.DEFINES += V8_SHARED USING_V8_SHARED diff --git a/src/src.pro b/src/src.pro index 1e072fbec75..a531355ae91 100644 --- a/src/src.pro +++ b/src/src.pro @@ -13,7 +13,9 @@ SRC_SUBDIRS += src_corelib SRC_SUBDIRS += src_network src_sql src_gui src_xml src_uitools src_widgets src_printsupport src_testlib src_platformsupport nacl: SRC_SUBDIRS -= src_network src_testlib !symbian:contains(QT_CONFIG, dbus):SRC_SUBDIRS += src_dbus + contains(QT_CONFIG, no-gui): SRC_SUBDIRS -= src_gui +!contains(QT_CONFIG, no-v8): SRC_SUBDIRS += src_v8 contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): SRC_SUBDIRS += src_opengl SRC_SUBDIRS += src_plugins @@ -30,6 +32,8 @@ src_winmain.subdir = $$QT_SOURCE_TREE/src/winmain src_winmain.target = sub-winmain src_corelib.subdir = $$QT_SOURCE_TREE/src/corelib src_corelib.target = sub-corelib +src_v8.subdir = $$QT_SOURCE_TREE/src/v8 +src_v8.target = sub-v8 src_xml.subdir = $$QT_SOURCE_TREE/src/xml src_xml.target = sub-xml src_uitools.subdir = $$QT_SOURCE_TREE/src/uitools diff --git a/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch new file mode 100644 index 00000000000..54a35fda9fe --- /dev/null +++ b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch @@ -0,0 +1,343 @@ +From e13ce09287a56c920d5ffdc5d4662d49f1838f16 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 15:47:20 +1000 +Subject: [PATCH 01/13] Add hashing and comparison methods to v8::String + +This allows us to more rapidly search for a v8::String inside +a hash of QStrings. +--- + include/v8.h | 44 ++++++++++++++++++++++++++++++ + src/api.cc | 43 +++++++++++++++++++++++++++++ + src/heap-inl.h | 2 + + src/heap.cc | 3 ++ + src/objects-inl.h | 1 + + src/objects.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + src/objects.h | 15 +++++++++- + 7 files changed, 182 insertions(+), 3 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index d15d024..bbd29e9 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -994,6 +994,48 @@ class String : public Primitive { + V8EXPORT int Utf8Length() const; + + /** ++ * Returns the hash of this string. ++ */ ++ V8EXPORT uint32_t Hash() const; ++ ++ struct CompleteHashData { ++ CompleteHashData() : length(0), hash(0), symbol_id(0) {} ++ int length; ++ uint32_t hash; ++ uint32_t symbol_id; ++ }; ++ ++ /** ++ * Returns the "complete" hash of the string. This is ++ * all the information about the string needed to implement ++ * a very efficient hash keyed on the string. ++ * ++ * The members of CompleteHashData are: ++ * length: The length of the string. Equivalent to Length() ++ * hash: The hash of the string. Equivalent to Hash() ++ * symbol_id: If the string is a sequential symbol, the symbol ++ * id, otherwise 0. If the symbol ids of two strings are ++ * the same (and non-zero) the two strings are identical. ++ * If the symbol ids are different the strings may still be ++ * identical, but an Equals() check must be performed. ++ */ ++ V8EXPORT CompleteHashData CompleteHash() const; ++ ++ /** ++ * Compute a hash value for the passed UTF16 string ++ * data. ++ */ ++ V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length); ++ V8EXPORT static uint32_t ComputeHash(char *string, int length); ++ ++ /** ++ * Returns true if this string is equal to the external ++ * string data provided. ++ */ ++ V8EXPORT bool Equals(uint16_t *string, int length); ++ V8EXPORT bool Equals(char *string, int length); ++ ++ /** + * Write the contents of the string to an external buffer. + * If no arguments are given, expects the buffer to be large + * enough to hold the entire string and NULL terminator. Copies +@@ -1023,6 +1065,8 @@ class String : public Primitive { + HINT_MANY_WRITES_EXPECTED = 1 + }; + ++ V8EXPORT uint16_t GetCharacter(int index); ++ + V8EXPORT int Write(uint16_t* buffer, + int start = 0, + int length = -1, +diff --git a/src/api.cc b/src/api.cc +index a2373cd..381935b 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3284,6 +3284,49 @@ int String::Utf8Length() const { + return str->Utf8Length(); + } + ++uint32_t String::Hash() const { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0; ++ return str->Hash(); ++} ++ ++String::CompleteHashData String::CompleteHash() const { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData(); ++ CompleteHashData result; ++ result.length = str->length(); ++ result.hash = str->Hash(); ++ if (str->IsSeqString()) ++ result.symbol_id = i::SeqString::cast(*str)->symbol_id(); ++ return result; ++} ++ ++uint32_t String::ComputeHash(uint16_t *string, int length) { ++ return i::HashSequentialString(string, length) >> i::String::kHashShift; ++} ++ ++uint32_t String::ComputeHash(char *string, int length) { ++ return i::HashSequentialString(string, length) >> i::String::kHashShift; ++} ++ ++uint16_t String::GetCharacter(int index) ++{ ++ i::Handle str = Utils::OpenHandle(this); ++ return str->Get(index); ++} ++ ++bool String::Equals(uint16_t *string, int length) { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} ++ ++bool String::Equals(char *string, int length) ++{ ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} + + int String::WriteUtf8(char* buffer, + int capacity, +diff --git a/src/heap-inl.h b/src/heap-inl.h +index 99737ed..f4fce7b 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -93,6 +93,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +diff --git a/src/heap.cc b/src/heap.cc +index 2b6c11f..930c97b 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, + String* answer = String::cast(result); + answer->set_length(chars); + answer->set_hash_field(hash_field); ++ SeqString::cast(result)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { + HeapObject::cast(result)->set_map(ascii_string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +@@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length, + HeapObject::cast(result)->set_map(string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 65aec5d..c82080d 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset) + + + SMI_ACCESSORS(String, length, kLengthOffset) ++SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset) + + + uint32_t String::hash_field() { +diff --git a/src/objects.cc b/src/objects.cc +index df61956..dc4b260 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate, + } + } + ++bool String::SlowEqualsExternal(uc16 *string, int length) { ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (lhs->IsFlat()) { ++ if (lhs->IsAsciiRepresentation()) { ++ Vector vec1 = lhs->ToAsciiVector(); ++ VectorIterator buf1(vec1); ++ VectorIterator ib(string, length); ++ return CompareStringContents(&buf1, &ib); ++ } else { ++ Vector vec1 = lhs->ToUC16Vector(); ++ Vector vec2(string, length); ++ return CompareRawStringContents(vec1, vec2); ++ } ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} ++ ++bool String::SlowEqualsExternal(char *string, int length) ++{ ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (StringShape(lhs).IsSequentialAscii()) { ++ const char* str1 = SeqAsciiString::cast(lhs)->GetChars(); ++ return CompareRawStringContents(Vector(str1, len), ++ Vector(string, len)); ++ } ++ ++ if (lhs->IsFlat()) { ++ Vector vec1 = lhs->ToUC16Vector(); ++ VectorIterator buf1(vec1); ++ VectorIterator buf2(string, length); ++ return CompareStringContents(&buf1, &buf2); ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} + + bool String::SlowEquals(String* other) { + // Fast check: negative check with lengths. +@@ -8655,9 +8715,24 @@ class AsciiSymbolKey : public SequentialSymbolKey { + + MaybeObject* AsObject() { + if (hash_field_ == 0) Hash(); +- return HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) { ++ while (true) { ++ Atomic32 my_symbol_id = next_symbol_id; ++ if (my_symbol_id > Smi::kMaxValue) ++ break; ++ if (my_symbol_id == NoBarrier_CompareAndSwap(&next_symbol_id, my_symbol_id, my_symbol_id + 1)) { ++ SeqString::cast(result->ToObjectUnchecked())->set_symbol_id(my_symbol_id); ++ break; ++ } ++ } ++ } ++ return result; + } ++ ++ static Atomic32 next_symbol_id; + }; ++Atomic32 AsciiSymbolKey::next_symbol_id = 1; + + + class TwoByteSymbolKey : public SequentialSymbolKey { +diff --git a/src/objects.h b/src/objects.h +index e966b3d..6e26f57 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -5359,6 +5359,9 @@ class String: public HeapObject { + bool IsAsciiEqualTo(Vector str); + bool IsTwoByteEqualTo(Vector str); + ++ bool SlowEqualsExternal(uc16 *string, int length); ++ bool SlowEqualsExternal(char *string, int length); ++ + // Return a UTF8 representation of the string. The string is null + // terminated but may optionally contain nulls. Length is returned + // in length_output if length_output is not a null pointer The string +@@ -5610,9 +5613,17 @@ class String: public HeapObject { + class SeqString: public String { + public: + ++ // Get and set the symbol id of the string ++ inline int symbol_id(); ++ inline void set_symbol_id(int value); ++ + // Casting. + static inline SeqString* cast(Object* obj); + ++ // Layout description. ++ static const int kSymbolIdOffset = String::kSize; ++ static const int kSize = kSymbolIdOffset + kPointerSize; ++ + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); + }; +@@ -5647,7 +5658,7 @@ class SeqAsciiString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential ASCII string. +@@ -5701,7 +5712,7 @@ class SeqTwoByteString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential two-byte string. +-- +1.7.2.3 + diff --git a/src/v8/0002-Add-a-bit-field-3-to-Map.patch b/src/v8/0002-Add-a-bit-field-3-to-Map.patch new file mode 100644 index 00000000000..dda9fa0dffe --- /dev/null +++ b/src/v8/0002-Add-a-bit-field-3-to-Map.patch @@ -0,0 +1,118 @@ +From 7c9cfff80b7864d5687432d424074e51712c4a07 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 15:55:26 +1000 +Subject: [PATCH 02/13] Add a bit field 3 to Map + +Bit field 3 will be used to add QML specific map flags. +--- + src/heap.cc | 2 ++ + src/objects-inl.h | 10 ++++++++++ + src/objects.cc | 2 ++ + src/objects.h | 9 ++++++++- + 4 files changed, 22 insertions(+), 1 deletions(-) + +diff --git a/src/heap.cc b/src/heap.cc +index 930c97b..900f462 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -1573,6 +1573,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, + reinterpret_cast(result)->set_unused_property_fields(0); + reinterpret_cast(result)->set_bit_field(0); + reinterpret_cast(result)->set_bit_field2(0); ++ reinterpret_cast(result)->set_bit_field3(0); + return result; + } + +@@ -1599,6 +1600,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { + map->set_unused_property_fields(0); + map->set_bit_field(0); + map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements)); ++ map->set_bit_field3(0); + + // If the map object is aligned fill the padding area with Smi 0 objects. + if (Map::kPadStart < Map::kSize) { +diff --git a/src/objects-inl.h b/src/objects-inl.h +index c82080d..cce3edd 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2430,6 +2430,16 @@ void Map::set_bit_field2(byte value) { + } + + ++byte Map::bit_field3() { ++ return READ_BYTE_FIELD(this, kBitField3Offset); ++} ++ ++ ++void Map::set_bit_field3(byte value) { ++ WRITE_BYTE_FIELD(this, kBitField3Offset, value); ++} ++ ++ + void Map::set_non_instance_prototype(bool value) { + if (value) { + set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); +diff --git a/src/objects.cc b/src/objects.cc +index dc4b260..79d7240 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -3614,6 +3614,7 @@ MaybeObject* Map::CopyDropDescriptors() { + } + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + Map::cast(result)->set_is_shared(false); + Map::cast(result)->ClearCodeCache(heap); + return result; +@@ -3642,6 +3643,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, + + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + + Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); + +diff --git a/src/objects.h b/src/objects.h +index 6e26f57..07e1089 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -3597,6 +3597,10 @@ class Map: public HeapObject { + inline byte bit_field2(); + inline void set_bit_field2(byte value); + ++ // Bit field 3. ++ inline byte bit_field3(); ++ inline void set_bit_field3(byte value); ++ + // Tells whether the object in the prototype property will be used + // for instances created from this function. If the prototype + // property is set to a value that is not a JSObject, the prototype +@@ -3844,7 +3848,7 @@ class Map: public HeapObject { + // Layout description. + static const int kInstanceSizesOffset = HeapObject::kHeaderSize; + static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; +- static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; ++ static const int kPrototypeOffset = POINTER_SIZE_ALIGN(kInstanceAttributesOffset + 2 * kIntSize); + static const int kConstructorOffset = kPrototypeOffset + kPointerSize; + static const int kInstanceDescriptorsOffset = + kConstructorOffset + kPointerSize; +@@ -3876,6 +3880,7 @@ class Map: public HeapObject { + static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1; + static const int kBitFieldOffset = kInstanceAttributesOffset + 2; + static const int kBitField2Offset = kInstanceAttributesOffset + 3; ++ static const int kBitField3Offset = kInstanceAttributesOffset + 4; + + STATIC_CHECK(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset); + +@@ -3898,6 +3903,8 @@ class Map: public HeapObject { + static const int kIsShared = 5; + static const int kHasExternalArrayElements = 6; + ++ // Bit positions for bit field 3 ++ + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; + static const int kCodeCacheEntryNameOffset = 0; +-- +1.7.2.3 + diff --git a/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch new file mode 100644 index 00000000000..50f97c7de8d --- /dev/null +++ b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch @@ -0,0 +1,364 @@ +From ae8688b53d67044f2c9b0cce25fc282b078610c1 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 16:21:02 +1000 +Subject: [PATCH 03/13] Add a "fallback" mode for named property interceptors + +By default interceptors are called before the normal property +resolution on objects. When an interceptor is installed as a +"fallback" interceptor, it is only called if the object doesn't +already have the property. + +In the case of a global object having an fallback interceptor, +the interceptor is not invoked at all for var or function +declarations. +--- + include/v8.h | 8 ++++++++ + src/api.cc | 29 +++++++++++++++++++++++++++++ + src/factory.cc | 4 ++++ + src/handles.cc | 6 ++++-- + src/handles.h | 3 ++- + src/objects-inl.h | 16 ++++++++++++++++ + src/objects.cc | 22 ++++++++++++++++------ + src/objects.h | 18 ++++++++++++++---- + src/runtime.cc | 11 ++++++----- + 9 files changed, 99 insertions(+), 18 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index bbd29e9..85452aa 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2169,6 +2169,7 @@ class V8EXPORT FunctionTemplate : public Template { + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle data); + void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, + IndexedPropertySetter setter, +@@ -2253,6 +2254,13 @@ class V8EXPORT ObjectTemplate : public Template { + NamedPropertyEnumerator enumerator = 0, + Handle data = Handle()); + ++ void SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter = 0, ++ NamedPropertyQuery query = 0, ++ NamedPropertyDeleter deleter = 0, ++ NamedPropertyEnumerator enumerator = 0, ++ Handle data = Handle()); ++ + /** + * Sets an indexed property handler on the object template. + * +diff --git a/src/api.cc b/src/api.cc +index 381935b..8b0b32a 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle data) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + if (IsDeadCheck(isolate, +@@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); + if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); + if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); ++ obj->set_is_fallback(i::Smi::FromInt(is_fallback)); + + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); +@@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, + query, + remover, + enumerator, ++ false, ++ data); ++} ++ ++ ++void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter, ++ NamedPropertyQuery query, ++ NamedPropertyDeleter remover, ++ NamedPropertyEnumerator enumerator, ++ Handle data) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ EnsureConstructor(this); ++ i::FunctionTemplateInfo* constructor = ++ i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); ++ i::Handle cons(constructor); ++ Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter, ++ setter, ++ query, ++ remover, ++ enumerator, ++ true, + data); + } + +diff --git a/src/factory.cc b/src/factory.cc +index 7dee66f..dcdc645 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -1058,6 +1058,10 @@ Handle Factory::CreateApiFunction( + // Set interceptor information in the map. + if (!obj->named_property_handler()->IsUndefined()) { + map->set_has_named_interceptor(); ++ ++ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler()); ++ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value(); ++ map->set_named_interceptor_is_fallback(is_fallback); + } + if (!obj->indexed_property_handler()->IsUndefined()) { + map->set_has_indexed_interceptor(); +diff --git a/src/handles.cc b/src/handles.cc +index 326de86..dd3a86c 100644 +--- a/src/handles.cc ++++ b/src/handles.cc +@@ -262,9 +262,11 @@ Handle SetProperty(Handle object, + Handle key, + Handle value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + CALL_HEAP_FUNCTION(object->GetIsolate(), +- object->SetProperty(*key, *value, attributes, strict_mode), ++ object->SetProperty(*key, *value, attributes, strict_mode, ++ skip_fallback_interceptor), + Object); + } + +diff --git a/src/handles.h b/src/handles.h +index 3839f37..4b42506 100644 +--- a/src/handles.h ++++ b/src/handles.h +@@ -188,7 +188,8 @@ Handle SetProperty(Handle object, + Handle key, + Handle value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + + Handle SetProperty(Handle object, + Handle key, +diff --git a/src/objects-inl.h b/src/objects-inl.h +index cce3edd..6aaca2f 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2521,6 +2521,21 @@ bool Map::is_shared() { + } + + ++void Map::set_named_interceptor_is_fallback(bool value) ++{ ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback)); ++ } ++} ++ ++bool Map::named_interceptor_is_fallback() ++{ ++ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0; ++} ++ ++ + JSFunction* Map::unchecked_constructor() { + return reinterpret_cast(READ_FIELD(this, kConstructorOffset)); + } +@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) + ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) + ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) + ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ++ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset) + + ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) + ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) +diff --git a/src/objects.cc b/src/objects.cc +index 79d7240..15e2cdb 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( + MaybeObject* JSObject::SetProperty(String* name, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + LookupResult result; +- LocalLookup(name, &result); ++ LocalLookup(name, &result, skip_fallback_interceptor); + return SetProperty(&result, name, value, attributes, strict_mode); + } + +@@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { + } + + +-void JSObject::LocalLookup(String* name, LookupResult* result) { ++void JSObject::LocalLookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + ASSERT(name->IsString()); + + Heap* heap = GetHeap(); +@@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) { + } + + // Check for lookup interceptor except when bootstrapping. +- if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { ++ bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive(); ++ if (wouldIntercept && !map()->named_interceptor_is_fallback()) { + result->InterceptorResult(this); + return; + } + + LocalLookupRealNamedProperty(name, result); ++ ++ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() && ++ map()->named_interceptor_is_fallback()) { ++ result->InterceptorResult(this); ++ return; ++ } + } + + +-void JSObject::Lookup(String* name, LookupResult* result) { ++void JSObject::Lookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + // Ecma-262 3rd 8.6.2.4 + Heap* heap = GetHeap(); + for (Object* current = this; + current != heap->null_value(); + current = JSObject::cast(current)->GetPrototype()) { +- JSObject::cast(current)->LocalLookup(name, result); ++ JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor); + if (result->IsProperty()) return; + } + result->NotFound(); +diff --git a/src/objects.h b/src/objects.h +index 07e1089..a209cd0 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1405,7 +1405,8 @@ class JSObject: public HeapObject { + MUST_USE_RESULT MaybeObject* SetProperty(String* key, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, + String* key, + Object* value, +@@ -1637,8 +1638,8 @@ class JSObject: public HeapObject { + + // Lookup a property. If found, the result is valid and has + // detailed information. +- void LocalLookup(String* name, LookupResult* result); +- void Lookup(String* name, LookupResult* result); ++ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); ++ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); + + // The following lookup functions skip interceptors. + void LocalLookupRealNamedProperty(String* name, LookupResult* result); +@@ -3714,6 +3715,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Whether the named interceptor is a fallback interceptor or not ++ inline void set_named_interceptor_is_fallback(bool value); ++ inline bool named_interceptor_is_fallback(); ++ ++ + // [prototype]: implicit prototype object. + DECL_ACCESSORS(prototype, Object) + +@@ -3904,6 +3911,7 @@ class Map: public HeapObject { + static const int kHasExternalArrayElements = 6; + + // Bit positions for bit field 3 ++ static const int kNamedInterceptorIsFallback = 0; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct { + DECL_ACCESSORS(deleter, Object) + DECL_ACCESSORS(enumerator, Object) + DECL_ACCESSORS(data, Object) ++ DECL_ACCESSORS(is_fallback, Smi) + + static inline InterceptorInfo* cast(Object* obj); + +@@ -6295,7 +6304,8 @@ class InterceptorInfo: public Struct { + static const int kDeleterOffset = kQueryOffset + kPointerSize; + static const int kEnumeratorOffset = kDeleterOffset + kPointerSize; + static const int kDataOffset = kEnumeratorOffset + kPointerSize; +- static const int kSize = kDataOffset + kPointerSize; ++ static const int kFallbackOffset = kDataOffset + kPointerSize; ++ static const int kSize = kFallbackOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); +diff --git a/src/runtime.cc b/src/runtime.cc +index 7335da8..660352c 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + // Lookup the property in the global object, and don't set the + // value of the variable if the property is already there. + LookupResult lookup; +- global->Lookup(*name, &lookup); ++ global->Lookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if the property is local by comparing the holder + // against the global object. The information will be used to +@@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + } + + LookupResult lookup; +- global->LocalLookup(*name, &lookup); ++ global->LocalLookup(*name, &lookup, true); + + PropertyAttributes attributes = is_const_property + ? static_cast(base | READ_ONLY) +@@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + name, + value, + attributes, +- strict_mode)); ++ strict_mode, ++ true)); + } + } + +@@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + JSObject* real_holder = global; + LookupResult lookup; + while (true) { +- real_holder->LocalLookup(*name, &lookup); ++ real_holder->LocalLookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if this is a redeclaration of something read-only. + if (lookup.IsReadOnly()) { +@@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + + global = isolate->context()->global(); + if (assign) { +- return global->SetProperty(*name, args[2], attributes, strict_mode); ++ return global->SetProperty(*name, args[2], attributes, strict_mode, true); + } + return isolate->heap()->undefined_value(); + } +-- +1.7.2.3 + diff --git a/src/v8/0004-Generalize-external-object-resources.patch b/src/v8/0004-Generalize-external-object-resources.patch new file mode 100644 index 00000000000..f44e7b21343 --- /dev/null +++ b/src/v8/0004-Generalize-external-object-resources.patch @@ -0,0 +1,894 @@ +From 4827116b12c50f6662794017c5a662b5dbb2da0b Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 16:55:35 +1000 +Subject: [PATCH 04/13] Generalize external object resources + +V8 was already able to manage and finalize an external string +resource. This change generalizes that mechanism to handle a +single generic external resource - a v8::Object::ExternalResource +derived instance - on normal JSObject's. + +This is useful for mapping C++ objects to JS objects where the +C++ object's memory is effectively owned by the JS Object, and +thus needs to destroyed when the JS Object is garbage collected. +The V8 mailing list suggests using a weak persistent handle for +this purpose, but that seems to incur a fairly massive performance +penalty for short lived objects as weak persistent handle callbacks +are not called until the object has been promoted into the old +object space. +--- + include/v8.h | 25 ++++++ + src/api.cc | 64 ++++++++++++++- + src/extensions/externalize-string-extension.cc | 4 +- + src/factory.cc | 11 +++ + src/heap-inl.h | 101 +++++++++++++++--------- + src/heap.cc | 68 ++++++++-------- + src/heap.h | 42 +++++----- + src/liveobjectlist.cc | 4 +- + src/mark-compact.cc | 21 +++--- + src/objects-inl.h | 41 +++++++++- + src/objects.h | 14 +++- + 11 files changed, 280 insertions(+), 115 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 85452aa..7f06ae7 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1630,6 +1630,25 @@ class Object : public Value { + /** Sets a native pointer in an internal field. */ + V8EXPORT void SetPointerInInternalField(int index, void* value); + ++ class V8EXPORT ExternalResource { // NOLINT ++ public: ++ ExternalResource() {} ++ virtual ~ExternalResource() {} ++ ++ protected: ++ virtual void Dispose() { delete this; } ++ ++ private: ++ // Disallow copying and assigning. ++ ExternalResource(const ExternalResource&); ++ void operator=(const ExternalResource&); ++ ++ friend class v8::internal::Heap; ++ }; ++ ++ V8EXPORT void SetExternalResource(ExternalResource *); ++ V8EXPORT ExternalResource *GetExternalResource(); ++ + // Testers for local properties. + V8EXPORT bool HasRealNamedProperty(Handle key); + V8EXPORT bool HasRealIndexedProperty(uint32_t index); +@@ -2331,6 +2350,12 @@ class V8EXPORT ObjectTemplate : public Template { + */ + void SetInternalFieldCount(int value); + ++ /** ++ * Sets whether the object can store an "external resource" object. ++ */ ++ bool HasExternalResource(); ++ void SetHasExternalResource(bool value); ++ + private: + ObjectTemplate(); + static Local New(Handle constructor); +diff --git a/src/api.cc b/src/api.cc +index 8b0b32a..1a6fbbb 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1294,6 +1294,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) { + } + + ++bool ObjectTemplate::HasExternalResource() ++{ ++ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(), ++ "v8::ObjectTemplate::HasExternalResource()")) { ++ return 0; ++ } ++ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined(); ++} ++ ++ ++void ObjectTemplate::SetHasExternalResource(bool value) ++{ ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ if (value) { ++ EnsureConstructor(this); ++ } ++ if (value) { ++ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1)); ++ } else { ++ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value()); ++ } ++} ++ ++ + // --- S c r i p t D a t a --- + + +@@ -3652,6 +3680,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { + } + + ++void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ENTER_V8(isolate); ++ i::Handle obj = Utils::OpenHandle(this); ++ if (CanBeEncodedAsSmi(resource)) { ++ obj->SetExternalResourceObject(EncodeAsSmi(resource)); ++ } else { ++ obj->SetExternalResourceObject(*isolate->factory()->NewProxy(static_cast((void *)resource))); ++ } ++ if (!obj->IsSymbol()) { ++ isolate->heap()->external_resource_table()->AddObject(*obj); ++ } ++} ++ ++ ++v8::Object::ExternalResource *v8::Object::GetExternalResource() { ++ i::Handle obj = Utils::OpenHandle(this); ++ i::Object* value = obj->GetExternalResourceObject(); ++ if (value->IsSmi()) { ++ return reinterpret_cast(i::Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ return reinterpret_cast(i::Proxy::cast(value)->proxy()); ++ } else { ++ return NULL; ++ } ++} ++ ++ + // --- E n v i r o n m e n t --- + + +@@ -4144,7 +4200,7 @@ Local v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle result = NewExternalStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4162,7 +4218,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +@@ -4175,7 +4231,7 @@ Local v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle result = NewExternalAsciiStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4194,7 +4250,7 @@ bool v8::String::MakeExternal( + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc +index b3f83fe..8e50904 100644 +--- a/src/extensions/externalize-string-extension.cc ++++ b/src/extensions/externalize-string-extension.cc +@@ -100,7 +100,7 @@ v8::Handle ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } else { +@@ -110,7 +110,7 @@ v8::Handle ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } +diff --git a/src/factory.cc b/src/factory.cc +index dcdc645..d530a75 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -997,15 +997,21 @@ Handle Factory::CreateApiFunction( + Handle construct_stub = isolate()->builtins()->JSConstructStubApi(); + + int internal_field_count = 0; ++ bool has_external_resource = false; ++ + if (!obj->instance_template()->IsUndefined()) { + Handle instance_template = + Handle( + ObjectTemplateInfo::cast(obj->instance_template())); + internal_field_count = + Smi::cast(instance_template->internal_field_count())->value(); ++ has_external_resource = ++ !instance_template->has_external_resource()->IsUndefined(); + } + + int instance_size = kPointerSize * internal_field_count; ++ if (has_external_resource) instance_size += kPointerSize; ++ + InstanceType type = INVALID_TYPE; + switch (instance_type) { + case JavaScriptObject: +@@ -1040,6 +1046,11 @@ Handle Factory::CreateApiFunction( + + Handle map = Handle(result->initial_map()); + ++ // Mark as having external data object if needed ++ if (has_external_resource) { ++ map->set_has_external_resource(true); ++ } ++ + // Mark as undetectable if needed. + if (obj->undetectable()) { + map->set_is_undetectable(); +diff --git a/src/heap-inl.h b/src/heap-inl.h +index f4fce7b..58e7adf 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -205,21 +205,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) { + } + + +-void Heap::FinalizeExternalString(String* string) { +- ASSERT(string->IsExternalString()); +- v8::String::ExternalStringResourceBase** resource_addr = +- reinterpret_cast( +- reinterpret_cast(string) + +- ExternalString::kResourceOffset - +- kHeapObjectTag); +- +- // Dispose of the C++ object if it has not already been disposed. +- if (*resource_addr != NULL) { +- (*resource_addr)->Dispose(); +- } ++void Heap::FinalizeExternalString(HeapObject* string) { ++ ASSERT(string->IsExternalString() || string->map()->has_external_resource()); ++ ++ if (string->IsExternalString()) { ++ v8::String::ExternalStringResourceBase** resource_addr = ++ reinterpret_cast( ++ reinterpret_cast(string) + ++ ExternalString::kResourceOffset - ++ kHeapObjectTag); ++ ++ // Dispose of the C++ object if it has not already been disposed. ++ if (*resource_addr != NULL) { ++ (*resource_addr)->Dispose(); ++ } + +- // Clear the resource pointer in the string. +- *resource_addr = NULL; ++ // Clear the resource pointer in the string. ++ *resource_addr = NULL; ++ } else { ++ JSObject *object = JSObject::cast(string); ++ Object *value = object->GetExternalResourceObject(); ++ v8::Object::ExternalResource *resource = 0; ++ if (value->IsSmi()) { ++ resource = reinterpret_cast(Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ resource = reinterpret_cast(Proxy::cast(value)->proxy()); ++ } ++ if (resource) { ++ resource->Dispose(); ++ } ++ } + } + + +@@ -556,53 +571,63 @@ inline bool Heap::allow_allocation(bool new_state) { + #endif + + +-void ExternalStringTable::AddString(String* string) { +- ASSERT(string->IsExternalString()); ++void ExternalResourceTable::AddString(String* string) { ++ ASSERT(string->IsExternalString() ); + if (heap_->InNewSpace(string)) { +- new_space_strings_.Add(string); ++ new_space_objects_.Add(string); ++ } else { ++ old_space_objects_.Add(string); ++ } ++} ++ ++ ++void ExternalResourceTable::AddObject(HeapObject* object) { ++ ASSERT(object->map()->has_external_resource()); ++ if (heap_->InNewSpace(object)) { ++ new_space_objects_.Add(object); + } else { +- old_space_strings_.Add(string); ++ old_space_objects_.Add(object); + } + } + + +-void ExternalStringTable::Iterate(ObjectVisitor* v) { +- if (!new_space_strings_.is_empty()) { +- Object** start = &new_space_strings_[0]; +- v->VisitPointers(start, start + new_space_strings_.length()); ++void ExternalResourceTable::Iterate(ObjectVisitor* v) { ++ if (!new_space_objects_.is_empty()) { ++ Object** start = &new_space_objects_[0]; ++ v->VisitPointers(start, start + new_space_objects_.length()); + } +- if (!old_space_strings_.is_empty()) { +- Object** start = &old_space_strings_[0]; +- v->VisitPointers(start, start + old_space_strings_.length()); ++ if (!old_space_objects_.is_empty()) { ++ Object** start = &old_space_objects_[0]; ++ v->VisitPointers(start, start + old_space_objects_.length()); + } + } + + + // Verify() is inline to avoid ifdef-s around its calls in release + // mode. +-void ExternalStringTable::Verify() { ++void ExternalResourceTable::Verify() { + #ifdef DEBUG +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- ASSERT(heap_->InNewSpace(new_space_strings_[i])); +- ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ ASSERT(heap_->InNewSpace(new_space_objects_[i])); ++ ASSERT(new_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ ASSERT(old_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } + #endif + } + + +-void ExternalStringTable::AddOldString(String* string) { +- ASSERT(string->IsExternalString()); +- ASSERT(!heap_->InNewSpace(string)); +- old_space_strings_.Add(string); ++void ExternalResourceTable::AddOldObject(HeapObject* object) { ++ ASSERT(object->IsExternalString() || object->map()->has_external_resource()); ++ ASSERT(!heap_->InNewSpace(object)); ++ old_space_objects_.Add(object); + } + + +-void ExternalStringTable::ShrinkNewStrings(int position) { +- new_space_strings_.Rewind(position); ++void ExternalResourceTable::ShrinkNewObjects(int position) { ++ new_space_objects_.Rewind(position); + Verify(); + } + +diff --git a/src/heap.cc b/src/heap.cc +index 900f462..bf2940e 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -155,7 +155,7 @@ Heap::Heap() + memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); + global_contexts_list_ = NULL; + mark_compact_collector_.heap_ = this; +- external_string_table_.heap_ = this; ++ external_resource_table_.heap_ = this; + } + + +@@ -1030,8 +1030,8 @@ void Heap::Scavenge() { + + new_space_front = DoScavenge(&scavenge_visitor, new_space_front); + +- UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + LiveObjectList::UpdateReferencesForScavengeGC(); + isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); +@@ -1053,38 +1053,38 @@ void Heap::Scavenge() { + } + + +-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++HeapObject* Heap::UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + MapWord first_word = HeapObject::cast(*p)->map_word(); + + if (!first_word.IsForwardingAddress()) { + // Unreachable external string can be finalized. +- heap->FinalizeExternalString(String::cast(*p)); ++ heap->FinalizeExternalString(HeapObject::cast(*p)); + return NULL; + } + + // String is still reachable. +- return String::cast(first_word.ToForwardingAddress()); ++ return HeapObject::cast(first_word.ToForwardingAddress()); + } + + +-void Heap::UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func) { +- external_string_table_.Verify(); ++void Heap::UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func) { ++ external_resource_table_.Verify(); + +- if (external_string_table_.new_space_strings_.is_empty()) return; ++ if (external_resource_table_.new_space_objects_.is_empty()) return; + +- Object** start = &external_string_table_.new_space_strings_[0]; +- Object** end = start + external_string_table_.new_space_strings_.length(); ++ Object** start = &external_resource_table_.new_space_objects_[0]; ++ Object** end = start + external_resource_table_.new_space_objects_.length(); + Object** last = start; + + for (Object** p = start; p < end; ++p) { + ASSERT(InFromSpace(*p)); +- String* target = updater_func(this, p); ++ HeapObject* target = updater_func(this, p); + + if (target == NULL) continue; + +- ASSERT(target->IsExternalString()); ++ ASSERT(target->IsExternalString() || target->map()->has_external_resource()); + + if (InNewSpace(target)) { + // String is still in new space. Update the table entry. +@@ -1092,12 +1092,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable( + ++last; + } else { + // String got promoted. Move it to the old string list. +- external_string_table_.AddOldString(target); ++ external_resource_table_.AddOldObject(target); + } + } + + ASSERT(last <= end); +- external_string_table_.ShrinkNewStrings(static_cast(last - start)); ++ external_resource_table_.ShrinkNewObjects(static_cast(last - start)); + } + + +@@ -4468,7 +4468,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { + v->Synchronize("symbol_table"); + if (mode != VISIT_ALL_IN_SCAVENGE) { + // Scavenge collections have special processing for this. +- external_string_table_.Iterate(v); ++ external_resource_table_.Iterate(v); + } + v->Synchronize("external_string_table"); + } +@@ -4970,7 +4970,7 @@ void Heap::TearDown() { + + isolate_->global_handles()->TearDown(); + +- external_string_table_.TearDown(); ++ external_resource_table_.TearDown(); + + new_space_.TearDown(); + +@@ -5835,31 +5835,31 @@ void TranscendentalCache::Clear() { + } + + +-void ExternalStringTable::CleanUp() { ++void ExternalResourceTable::CleanUp() { + int last = 0; +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- if (heap_->InNewSpace(new_space_strings_[i])) { +- new_space_strings_[last++] = new_space_strings_[i]; ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ if (new_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ if (heap_->InNewSpace(new_space_objects_[i])) { ++ new_space_objects_[last++] = new_space_objects_[i]; + } else { +- old_space_strings_.Add(new_space_strings_[i]); ++ old_space_objects_.Add(new_space_objects_[i]); + } + } +- new_space_strings_.Rewind(last); ++ new_space_objects_.Rewind(last); + last = 0; +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- old_space_strings_[last++] = old_space_strings_[i]; ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ if (old_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ old_space_objects_[last++] = old_space_objects_[i]; + } +- old_space_strings_.Rewind(last); ++ old_space_objects_.Rewind(last); + Verify(); + } + + +-void ExternalStringTable::TearDown() { +- new_space_strings_.Free(); +- old_space_strings_.Free(); ++void ExternalResourceTable::TearDown() { ++ new_space_objects_.Free(); ++ old_space_objects_.Free(); + } + + +diff --git a/src/heap.h b/src/heap.h +index ae4e9e7..8cbf378 100644 +--- a/src/heap.h ++++ b/src/heap.h +@@ -237,8 +237,8 @@ class Isolate; + class WeakObjectRetainer; + + +-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap, +- Object** pointer); ++typedef HeapObject* (*ExternalResourceTableUpdaterCallback)(Heap* heap, ++ Object** pointer); + + typedef bool (*DirtyRegionCallback)(Heap* heap, + Address start, +@@ -284,43 +284,45 @@ class PromotionQueue { + }; + + +-// External strings table is a place where all external strings are +-// registered. We need to keep track of such strings to properly +-// finalize them. +-class ExternalStringTable { ++// External resource table is a place where all external strings and ++// objects with an external resource are registered. We need to keep ++// track of such strings to properly finalize them. ++class ExternalResourceTable { + public: + // Registers an external string. + inline void AddString(String* string); ++ // Registers an external object. ++ inline void AddObject(HeapObject* object); + + inline void Iterate(ObjectVisitor* v); + + // Restores internal invariant and gets rid of collected strings. +- // Must be called after each Iterate() that modified the strings. ++ // Must be called after each Iterate() that modified the objects. + void CleanUp(); + + // Destroys all allocated memory. + void TearDown(); + + private: +- ExternalStringTable() { } ++ ExternalResourceTable() { } + + friend class Heap; + + inline void Verify(); + +- inline void AddOldString(String* string); ++ inline void AddOldObject(HeapObject* object); + + // Notifies the table that only a prefix of the new list is valid. +- inline void ShrinkNewStrings(int position); ++ inline void ShrinkNewObjects(int position); + + // To speed up scavenge collections new space string are kept + // separate from old space strings. +- List new_space_strings_; +- List old_space_strings_; ++ List new_space_objects_; ++ List old_space_objects_; + + Heap* heap_; + +- DISALLOW_COPY_AND_ASSIGN(ExternalStringTable); ++ DISALLOW_COPY_AND_ASSIGN(ExternalResourceTable); + }; + + +@@ -753,7 +755,7 @@ class Heap { + + // Finalizes an external string by deleting the associated external + // data and clearing the resource pointer. +- inline void FinalizeExternalString(String* string); ++ inline void FinalizeExternalString(HeapObject* string); + + // Allocates an uninitialized object. The memory is non-executable if the + // hardware and OS allow. +@@ -1191,8 +1193,8 @@ class Heap { + survived_since_last_expansion_ += survived; + } + +- void UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func); ++ void UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func); + + void ProcessWeakReferences(WeakObjectRetainer* retainer); + +@@ -1228,8 +1230,8 @@ class Heap { + return &mark_compact_collector_; + } + +- ExternalStringTable* external_string_table() { +- return &external_string_table_; ++ ExternalResourceTable* external_resource_table() { ++ return &external_resource_table_; + } + + inline Isolate* isolate(); +@@ -1462,7 +1464,7 @@ class Heap { + // Performs a minor collection in new generation. + void Scavenge(); + +- static String* UpdateNewSpaceReferenceInExternalStringTableEntry( ++ static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry( + Heap* heap, + Object** pointer); + +@@ -1593,7 +1595,7 @@ class Heap { + // configured through the API until it is setup. + bool configured_; + +- ExternalStringTable external_string_table_; ++ ExternalResourceTable external_resource_table_; + + bool is_safe_to_read_maps_; + +diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc +index 5795a6b..8866e58 100644 +--- a/src/liveobjectlist.cc ++++ b/src/liveobjectlist.cc +@@ -1989,7 +1989,7 @@ Object* LiveObjectList::PrintObj(int obj_id) { + ASSERT(resource->IsAscii()); + Handle dump_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*dump_string); ++ ExternalResourceTable::AddString(*dump_string); + return *dump_string; + } else { + delete resource; +@@ -2193,7 +2193,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { + ASSERT(resource->IsAscii()); + Handle path_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*path_string); ++ ExternalResourceTable::AddString(*path_string); + return *path_string; + } else { + delete resource; +diff --git a/src/mark-compact.cc b/src/mark-compact.cc +index 68a5062..1b1e361 100644 +--- a/src/mark-compact.cc ++++ b/src/mark-compact.cc +@@ -163,7 +163,7 @@ void MarkCompactCollector::Finish() { + // objects (empty string, illegal builtin). + heap()->isolate()->stub_cache()->Clear(); + +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.CleanUp(); + + // If we've just compacted old space there's no reason to check the + // fragmentation limit. Just return. +@@ -1019,8 +1019,9 @@ class SymbolTableCleaner : public ObjectVisitor { + + // Since no objects have yet been moved we can safely access the map of + // the object. +- if ((*p)->IsExternalString()) { +- heap_->FinalizeExternalString(String::cast(*p)); ++ if ((*p)->IsExternalString() || ++ (*p)->IsHeapObject() && HeapObject::cast(*p)->map()->has_external_resource()) { ++ heap_->FinalizeExternalString(HeapObject::cast(*p)); + } + // Set the entry to null_value (as deleted). + *p = heap_->raw_unchecked_null_value(); +@@ -1433,8 +1434,8 @@ void MarkCompactCollector::MarkLiveObjects() { + SymbolTableCleaner v(heap()); + symbol_table->IterateElements(&v); + symbol_table->ElementsRemoved(v.PointersRemoved()); +- heap()->external_string_table_.Iterate(&v); +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.Iterate(&v); ++ heap()->external_resource_table_.CleanUp(); + + // Process the weak references. + MarkCompactWeakObjectRetainer mark_compact_object_retainer; +@@ -1948,11 +1949,11 @@ static void UpdatePointerToNewGen(HeapObject** p) { + } + + +-static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + Address old_addr = HeapObject::cast(*p)->address(); + Address new_addr = Memory::Address_at(old_addr); +- return String::cast(HeapObject::FromAddress(new_addr)); ++ return HeapObject::FromAddress(new_addr); + } + + +@@ -2083,8 +2084,8 @@ static void SweepNewSpace(Heap* heap, NewSpace* space) { + updating_visitor.VisitPointer(heap->global_contexts_list_address()); + + // Update pointers from external string table. +- heap->UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ heap->UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + // All pointers were updated. Update auxiliary allocation info. + heap->IncrementYoungSurvivorsCounter(survivors_size); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 6aaca2f..231b835 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1392,13 +1392,13 @@ int JSObject::GetInternalFieldCount() { + // Make sure to adjust for the number of in-object properties. These + // properties do contribute to the size, but are not internal fields. + return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - +- map()->inobject_properties(); ++ map()->inobject_properties() - map()->has_external_resource()?1:0; + } + + + int JSObject::GetInternalFieldOffset(int index) { + ASSERT(index < GetInternalFieldCount() && index >= 0); +- return GetHeaderSize() + (kPointerSize * index); ++ return GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + } + + +@@ -1407,7 +1407,7 @@ Object* JSObject::GetInternalField(int index) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); ++ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0))); + } + + +@@ -1416,12 +1416,29 @@ void JSObject::SetInternalField(int index, Object* value) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- int offset = GetHeaderSize() + (kPointerSize * index); ++ int offset = GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); + } + + ++void JSObject::SetExternalResourceObject(Object *value) { ++ ASSERT(map()->has_external_resource()); ++ int offset = GetHeaderSize(); ++ WRITE_FIELD(this, offset, value); ++ WRITE_BARRIER(this, offset); ++} ++ ++ ++Object *JSObject::GetExternalResourceObject() { ++ if (map()->has_external_resource()) { ++ return READ_FIELD(this, GetHeaderSize()); ++ } else { ++ return GetHeap()->undefined_value(); ++ } ++} ++ ++ + // Access fast-case object properties at index. The use of these routines + // is needed to correctly distinguish between properties stored in-object and + // properties stored in the properties array. +@@ -2521,6 +2538,20 @@ bool Map::is_shared() { + } + + ++void Map::set_has_external_resource(bool value) { ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kHasExternalResource)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kHasExternalResource)); ++ } ++} ++ ++bool Map::has_external_resource() ++{ ++ return ((1 << kHasExternalResource) & bit_field3()) != 0; ++} ++ ++ + void Map::set_named_interceptor_is_fallback(bool value) + { + if (value) { +@@ -3017,6 +3048,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) + ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) + ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) ++ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, ++ kHasExternalResourceOffset) + + ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) + ACCESSORS(SignatureInfo, args, Object, kArgsOffset) +diff --git a/src/objects.h b/src/objects.h +index a209cd0..1bdb5c7 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1636,6 +1636,9 @@ class JSObject: public HeapObject { + inline Object* GetInternalField(int index); + inline void SetInternalField(int index, Object* value); + ++ inline void SetExternalResourceObject(Object *); ++ inline Object *GetExternalResourceObject(); ++ + // Lookup a property. If found, the result is valid and has + // detailed information. + void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); +@@ -3715,6 +3718,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Tells whether the instance has the space for an external resource ++ // object ++ inline void set_has_external_resource(bool value); ++ inline bool has_external_resource(); ++ + + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); +@@ -3912,6 +3921,7 @@ class Map: public HeapObject { + + // Bit positions for bit field 3 + static const int kNamedInterceptorIsFallback = 0; ++ static const int kHasExternalResource = 1; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6426,6 +6436,7 @@ class ObjectTemplateInfo: public TemplateInfo { + public: + DECL_ACCESSORS(constructor, Object) + DECL_ACCESSORS(internal_field_count, Object) ++ DECL_ACCESSORS(has_external_resource, Object) + + static inline ObjectTemplateInfo* cast(Object* obj); + +@@ -6442,7 +6453,8 @@ class ObjectTemplateInfo: public TemplateInfo { + static const int kConstructorOffset = TemplateInfo::kHeaderSize; + static const int kInternalFieldCountOffset = + kConstructorOffset + kPointerSize; +- static const int kSize = kInternalFieldCountOffset + kPointerSize; ++ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; ++ static const int kSize = kHasExternalResourceOffset + kPointerSize; + }; + + +-- +1.7.2.3 + diff --git a/src/v8/0005-Introduce-a-QML-compilation-mode.patch b/src/v8/0005-Introduce-a-QML-compilation-mode.patch new file mode 100644 index 00000000000..b464e612663 --- /dev/null +++ b/src/v8/0005-Introduce-a-QML-compilation-mode.patch @@ -0,0 +1,1777 @@ +From fd7d475e298e5b63cd6383c78cc900635c82aa38 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 18:26:19 +1000 +Subject: [PATCH 05/13] Introduce a QML compilation mode + +In QML mode, there is a second global object - known as the QML +global object. During property resolution, if a property is not +present on the JS global object, it is resolve on the QML global +object. + +This global object behavior is only enabled if a script is being +compiled in QML mode. The object to use as the QML global object +is passed as a parameter to the Script::Run() method. Any function +closures etc. created during the run will retain a reference to this +object, so different objects can be passed in different script +runs. +--- + include/v8.h | 18 ++++++++-- + src/api.cc | 52 ++++++++++++++++++++++++----- + src/arm/code-stubs-arm.cc | 4 ++ + src/arm/full-codegen-arm.cc | 26 ++++++++------ + src/arm/lithium-arm.cc | 2 +- + src/arm/lithium-arm.h | 6 +++- + src/arm/lithium-codegen-arm.cc | 7 ++-- + src/arm/macro-assembler-arm.h | 5 +++ + src/ast-inl.h | 5 +++ + src/ast.h | 1 + + src/code-stubs.h | 2 +- + src/compiler.cc | 15 +++++++- + src/compiler.h | 22 ++++++++++-- + src/contexts.cc | 23 +++++++++++++ + src/contexts.h | 4 ++ + src/execution.cc | 28 +++++++++++++-- + src/execution.h | 6 +++ + src/full-codegen.cc | 3 +- + src/full-codegen.h | 1 + + src/heap.cc | 2 + + src/hydrogen-instructions.h | 10 ++++- + src/hydrogen.cc | 2 + + src/ia32/code-stubs-ia32.cc | 7 ++++ + src/ia32/full-codegen-ia32.cc | 26 ++++++++------ + src/ia32/lithium-codegen-ia32.cc | 7 ++-- + src/ia32/lithium-ia32.cc | 2 +- + src/ia32/lithium-ia32.h | 6 +++- + src/ia32/macro-assembler-ia32.h | 5 +++ + src/objects-inl.h | 12 +++++++ + src/objects.h | 5 +++ + src/parser.cc | 27 +++++++++++++-- + src/parser.h | 4 ++- + src/prettyprinter.cc | 3 ++ + src/runtime.cc | 68 ++++++++++++++++++++++++------------- + src/runtime.h | 8 ++-- + src/scopes.cc | 10 +++++ + src/scopes.h | 7 ++++ + src/variables.cc | 3 +- + src/variables.h | 5 +++ + src/x64/code-stubs-x64.cc | 4 ++ + src/x64/full-codegen-x64.cc | 26 ++++++++------ + src/x64/lithium-codegen-x64.cc | 7 ++-- + src/x64/lithium-x64.cc | 2 +- + src/x64/lithium-x64.h | 6 +++ + src/x64/macro-assembler-x64.h | 5 +++ + 45 files changed, 391 insertions(+), 108 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 7f06ae7..a858eae 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -577,6 +577,10 @@ class ScriptOrigin { + */ + class V8EXPORT Script { + public: ++ enum CompileFlags { ++ Default = 0x00, ++ QmlMode = 0x01 ++ }; + + /** + * Compiles the specified script (context-independent). +@@ -596,7 +600,8 @@ class V8EXPORT Script { + static Local