summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-08-30 11:51:17 +0200
committerSamuel Rødal <samuel.rodal@nokia.com>2011-08-30 11:51:20 +0200
commit42f2da5e6b543e698fc4f036c45ebb15078409c8 (patch)
tree2d688b1a812d8410d4ae85283d5e413957000e11
parente9962cc300a805ce09a02ce0c9ae23ceaf8073bb (diff)
parent009f3d14045e2e2a6eff8c87a8da9eaa621c5249 (diff)
Merge remote branch 'gerrit/master' into refactor
Conflicts: src/src.pro Change-Id: Ic04fb170b82e86dc3cef6fe979f8fb709db10daf
-rw-r--r--.gitmodules3
-rwxr-xr-xbin/syncqt9
-rw-r--r--config.tests/x11/fontconfig/fontconfig.pro1
-rwxr-xr-xconfigure30
m---------src/3rdparty/v80
-rw-r--r--src/corelib/kernel/qobject.cpp5
-rw-r--r--src/corelib/kernel/qobject_p.h1
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp659
-rw-r--r--src/gui/math3d/qmatrix4x4.h321
-rw-r--r--src/modules/qt_v8.pri16
-rw-r--r--src/src.pro4
-rw-r--r--src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch343
-rw-r--r--src/v8/0002-Add-a-bit-field-3-to-Map.patch118
-rw-r--r--src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch364
-rw-r--r--src/v8/0004-Generalize-external-object-resources.patch894
-rw-r--r--src/v8/0005-Introduce-a-QML-compilation-mode.patch1777
-rw-r--r--src/v8/0006-Allow-access-to-the-calling-script-data.patch48
-rw-r--r--src/v8/0007-Fix-warnings.patch46
-rw-r--r--src/v8/0008-Add-custom-object-compare-callback.patch489
-rw-r--r--src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch286
-rw-r--r--src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch397
-rw-r--r--src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch63
-rw-r--r--src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch116
-rw-r--r--src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch15
-rw-r--r--src/v8/README1
-rw-r--r--src/v8/v8.pri260
-rw-r--r--src/v8/v8.pro24
-rw-r--r--src/v8/v8base.pri19
-rw-r--r--sync.profile7
-rw-r--r--tests/auto/auto.pro1
-rw-r--r--tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp108
-rw-r--r--tests/auto/v8.pro3
-rw-r--r--tests/auto/v8/Makefile.nonqt16
-rw-r--r--tests/auto/v8/README.txt13
-rw-r--r--tests/auto/v8/tst_v8.cpp80
-rw-r--r--tests/auto/v8/v8.pro9
-rw-r--r--tests/auto/v8/v8main.cpp17
-rw-r--r--tests/auto/v8/v8test.cpp254
-rw-r--r--tests/auto/v8/v8test.h55
-rw-r--r--tools/configure/configureapp.cpp23
40 files changed, 6462 insertions, 433 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..183f5b46cc
--- /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 4eab929b30..f28b2bf60a 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 718a8204bc..8360774035 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 7f8491ed70..6a7027e46a 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
+Subproject dc2cad4f8fc88c52fcea09b8d0262d35cd32dc4
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 2d280f14f7..0f314d45f1 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 9151e8eb7b..e7233c5ba9 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 cef92af66b..1797564a98 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;
+
+ // 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;
+
+ // 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;
+ }
}
-
- // 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);
-
- // 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;
}
/*!
@@ -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 bfbe4b9793..2c98dd03e3 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 0000000000..89d6c263e8
--- /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 1e072fbec7..a531355ae9 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 0000000000..54a35fda9f
--- /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 <aaron.kennedy@nokia.com>
+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<i::String> str = Utils::OpenHandle(this);
++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
++ return str->Hash();
++}
++
++String::CompleteHashData String::CompleteHash() const {
++ i::Handle<i::String> 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<i::uc16>(string, length) >> i::String::kHashShift;
++}
++
++uint32_t String::ComputeHash(char *string, int length) {
++ return i::HashSequentialString<char>(string, length) >> i::String::kHashShift;
++}
++
++uint16_t String::GetCharacter(int index)
++{
++ i::Handle<i::String> str = Utils::OpenHandle(this);
++ return str->Get(index);
++}
++
++bool String::Equals(uint16_t *string, int length) {
++ i::Handle<i::String> 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<i::String> 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<const char> 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<const uc16> 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<const char> vec1 = lhs->ToAsciiVector();
++ VectorIterator<char> buf1(vec1);
++ VectorIterator<uc16> ib(string, length);
++ return CompareStringContents(&buf1, &ib);
++ } else {
++ Vector<const uc16> vec1 = lhs->ToUC16Vector();
++ Vector<const uc16> vec2(string, length);
++ return CompareRawStringContents(vec1, vec2);
++ }
++ } else {
++ Isolate* isolate = GetIsolate();
++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
++ VectorIterator<uc16> 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<const char>(str1, len),
++ Vector<const char>(string, len));
++ }
++
++ if (lhs->IsFlat()) {
++ Vector<const uc16> vec1 = lhs->ToUC16Vector();
++ VectorIterator<const uc16> buf1(vec1);
++ VectorIterator<char> buf2(string, length);
++ return CompareStringContents(&buf1, &buf2);
++ } else {
++ Isolate* isolate = GetIsolate();
++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
++ VectorIterator<char> 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<char> {
+
+ 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<uc16> {
+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<const char> str);
+ bool IsTwoByteEqualTo(Vector<const uc16> 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 0000000000..dda9fa0dff
--- /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 <aaron.kennedy@nokia.com>
+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<Map*>(result)->set_unused_property_fields(0);
+ reinterpret_cast<Map*>(result)->set_bit_field(0);
+ reinterpret_cast<Map*>(result)->set_bit_field2(0);
++ reinterpret_cast<Map*>(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 0000000000..50f97c7de8
--- /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 <aaron.kennedy@nokia.com>
+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<Value> data);
+ void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
+ IndexedPropertySetter setter,
+@@ -2253,6 +2254,13 @@ class V8EXPORT ObjectTemplate : public Template {
+ NamedPropertyEnumerator enumerator = 0,
+ Handle<Value> data = Handle<Value>());
+
++ void SetFallbackPropertyHandler(NamedPropertyGetter getter,
++ NamedPropertySetter setter = 0,
++ NamedPropertyQuery query = 0,
++ NamedPropertyDeleter deleter = 0,
++ NamedPropertyEnumerator enumerator = 0,
++ Handle<Value> data = Handle<Value>());
++
+ /**
+ * 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<Value> 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<Value> 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<i::FunctionTemplateInfo> 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<JSFunction> 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<Object> SetProperty(Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> 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<Object> SetProperty(Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool skip_fallback_interceptor = false);
+
+ Handle<Object> SetProperty(Handle<Object> object,
+ Handle<Object> 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<JSFunction*>(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<PropertyAttributes>(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 0000000000..f44e7b2134
--- /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 <aaron.kennedy@nokia.com>
+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<String> 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<ObjectTemplate> New(Handle<FunctionTemplate> 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<i::JSObject> obj = Utils::OpenHandle(this);
++ if (CanBeEncodedAsSmi(resource)) {
++ obj->SetExternalResourceObject(EncodeAsSmi(resource));
++ } else {
++ obj->SetExternalResourceObject(*isolate->factory()->NewProxy(static_cast<i::Address>((void *)resource)));
++ }
++ if (!obj->IsSymbol()) {
++ isolate->heap()->external_resource_table()->AddObject(*obj);
++ }
++}
++
++
++v8::Object::ExternalResource *v8::Object::GetExternalResource() {
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ i::Object* value = obj->GetExternalResourceObject();
++ if (value->IsSmi()) {
++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value));
++ } else if (value->IsProxy()) {
++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Proxy::cast(value)->proxy());
++ } else {
++ return NULL;
++ }
++}
++
++
+ // --- E n v i r o n m e n t ---
+
+
+@@ -4144,7 +4200,7 @@ Local<String> v8::String::NewExternal(
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> 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<String> v8::String::NewExternal(
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> 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<v8::Value> 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<v8::Value> 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<JSFunction> Factory::CreateApiFunction(
+ Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
+
+ int internal_field_count = 0;
++ bool has_external_resource = false;
++
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance_template =
+ Handle<ObjectTemplateInfo>(
+ 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<JSFunction> Factory::CreateApiFunction(
+
+ Handle<Map> map = Handle<Map>(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<v8::String::ExternalStringResourceBase**>(
+- reinterpret_cast<byte*>(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<v8::String::ExternalStringResourceBase**>(
++ reinterpret_cast<byte*>(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<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value));
++ } else if (value->IsProxy()) {
++ resource = reinterpret_cast<v8::Object::ExternalResource*>(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<int>(last - start));
++ external_resource_table_.ShrinkNewObjects(static_cast<int>(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<Object*> new_space_strings_;
+- List<Object*> old_space_strings_;
++ List<Object*> new_space_objects_;
++ List<Object*> 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<String> 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<String> 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 0000000000..b464e61266
--- /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 <aaron.kennedy@nokia.com>
+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<Script> New(Handle<String> source,
+ ScriptOrigin* origin = NULL,
+ ScriptData* pre_data = NULL,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script using the specified file name
+@@ -609,7 +614,8 @@ class V8EXPORT Script {
+ * will use the currently entered context).
+ */
+ static Local<Script> New(Handle<String> source,
+- Handle<Value> file_name);
++ Handle<Value> file_name,
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script (bound to current context).
+@@ -630,7 +636,8 @@ class V8EXPORT Script {
+ static Local<Script> Compile(Handle<String> source,
+ ScriptOrigin* origin = NULL,
+ ScriptData* pre_data = NULL,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script using the specified file name
+@@ -647,7 +654,8 @@ class V8EXPORT Script {
+ */
+ static Local<Script> Compile(Handle<String> source,
+ Handle<Value> file_name,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Runs the script returning the resulting value. If the script is
+@@ -657,6 +665,7 @@ class V8EXPORT Script {
+ * compiled.
+ */
+ Local<Value> Run();
++ Local<Value> Run(Handle<Object> qml);
+
+ /**
+ * Returns the script id value.
+@@ -3326,6 +3335,7 @@ class V8EXPORT Context {
+ * JavaScript frames an empty handle is returned.
+ */
+ static Local<Context> GetCalling();
++ static Local<Object> GetCallingQmlGlobal();
+
+ /**
+ * Sets the security token for the context. To access an object in
+diff --git a/src/api.cc b/src/api.cc
+index 1a6fbbb..39767f4 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -1372,7 +1372,8 @@ ScriptData* ScriptData::New(const char* data, int length) {
+ Local<Script> Script::New(v8::Handle<String> source,
+ v8::ScriptOrigin* origin,
+ v8::ScriptData* pre_data,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
+ LOG_API(isolate, "Script::New");
+@@ -1409,7 +1410,8 @@ Local<Script> Script::New(v8::Handle<String> source,
+ NULL,
+ pre_data_impl,
+ Utils::OpenHandle(*script_data),
+- i::NOT_NATIVES_CODE);
++ i::NOT_NATIVES_CODE,
++ compile_flags);
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
+ return Local<Script>(ToApi<Script>(result));
+@@ -1417,21 +1419,23 @@ Local<Script> Script::New(v8::Handle<String> source,
+
+
+ Local<Script> Script::New(v8::Handle<String> source,
+- v8::Handle<Value> file_name) {
++ v8::Handle<Value> file_name,
++ v8::Script::CompileFlags compile_flags) {
+ ScriptOrigin origin(file_name);
+- return New(source, &origin);
++ return New(source, &origin, 0, Handle<String>(), compile_flags);
+ }
+
+
+ Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::ScriptOrigin* origin,
+ v8::ScriptData* pre_data,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
+ LOG_API(isolate, "Script::Compile");
+ ENTER_V8(isolate);
+- Local<Script> generic = New(source, origin, pre_data, script_data);
++ Local<Script> generic = New(source, origin, pre_data, script_data, compile_flags);
+ if (generic.IsEmpty())
+ return generic;
+ i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
+@@ -1447,13 +1451,18 @@ Local<Script> Script::Compile(v8::Handle<String> source,
+
+ Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::Handle<Value> file_name,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ ScriptOrigin origin(file_name);
+- return Compile(source, &origin, 0, script_data);
++ return Compile(source, &origin, 0, script_data, compile_flags);
+ }
+
+
+ Local<Value> Script::Run() {
++ return Run(Handle<Object>());
++}
++
++Local<Value> Script::Run(Handle<Object> qml) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
+ LOG_API(isolate, "Script::Run");
+@@ -1472,10 +1481,11 @@ Local<Value> Script::Run() {
+ fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
+ }
+ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> qmlglobal = Utils::OpenHandle(*qml);
+ i::Handle<i::Object> receiver(
+ isolate->context()->global_proxy(), isolate);
+ i::Handle<i::Object> result =
+- i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
++ i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception, qmlglobal);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+ raw_result = *result;
+ }
+@@ -3943,6 +3953,30 @@ v8::Local<v8::Context> Context::GetCalling() {
+ }
+
+
++v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
++ i::Isolate* isolate = i::Isolate::Current();
++ if (IsDeadCheck(isolate, "v8::Context::GetCallingQmlGlobal()")) {
++ return Local<Object>();
++ }
++
++ i::Context *context = isolate->context();
++ if (!context->qml_global()->IsUndefined()) {
++ i::Handle<i::Object> qmlglobal(context->qml_global());
++ return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal));
++ }
++
++ i::JavaScriptFrameIterator it;
++ if (it.done()) return Local<Object>();
++ context = i::Context::cast(it.frame()->context());
++ if (!context->qml_global()->IsUndefined()) {
++ i::Handle<i::Object> qmlglobal(context->qml_global());
++ return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal));
++ } else {
++ return Local<Object>();
++ }
++}
++
++
+ v8::Local<v8::Object> Context::Global() {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+ return Local<v8::Object>();
+diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
+index 8c147f9..a2626bf 100644
+--- a/src/arm/code-stubs-arm.cc
++++ b/src/arm/code-stubs-arm.cc
+@@ -166,6 +166,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
+ __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ str(r1, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX)));
+
++ // Copy the qml global object from the surrounding context.
++ __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++ __ str(r1, MemOperand(r0, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++
+ // Initialize the rest of the slots to undefined.
+ __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
+diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
+index 871b453..a69f10d 100644
+--- a/src/arm/full-codegen-arm.cc
++++ b/src/arm/full-codegen-arm.cc
+@@ -154,12 +154,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment cmnt(masm_, "[ Allocate local context");
+ // Argument to NewContext is the function, which is in r1.
+ __ push(r1);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -1247,9 +1248,9 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+ __ bind(&fast);
+ }
+
+- __ ldr(r0, GlobalObjectOperand());
++ __ ldr(r0, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(r2, Operand(slot->var()->name()));
+- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global())
+ ? RelocInfo::CODE_TARGET
+ : RelocInfo::CODE_TARGET_CONTEXT;
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+@@ -1268,10 +1269,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in r2 and the global
+ // object (receiver) in r0.
+- __ ldr(r0, GlobalObjectOperand());
++ __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(r2, Operand(var->name()));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(r0);
+
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+@@ -1893,11 +1894,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+ // assignment. Right-hand-side value is passed in r0, variable name in
+ // r2, and the global object in r1.
+ __ mov(r2, Operand(var->name()));
+- __ ldr(r1, GlobalObjectOperand());
++ __ ldr(r1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (op == Token::INIT_CONST) {
+ // Like var declarations, const declarations are hoisted to function
+@@ -2184,10 +2185,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
+ // Push the strict mode flag.
+ __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
+ __ push(r1);
++ // Push the qml mode flag.
++ __ mov(r1, Operand(Smi::FromInt(is_qml_mode())));
++ __ push(r1);
+
+ __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
+ ? Runtime::kResolvePossiblyDirectEvalNoLookup
+- : Runtime::kResolvePossiblyDirectEval, 4);
++ : Runtime::kResolvePossiblyDirectEval, 5);
+ }
+
+
+@@ -2263,9 +2267,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
+ context()->DropAndPlug(1, r0);
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Push global object as receiver for the call IC.
+- __ ldr(r0, GlobalObjectOperand());
++ __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ push(r0);
+- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (var != NULL && var->AsSlot() != NULL &&
+ var->AsSlot()->type() == Slot::LOOKUP) {
+ // Call to a lookup slot (dynamically introduced variable).
+diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
+index 3f1d15b..8406a96 100644
+--- a/src/arm/lithium-arm.cc
++++ b/src/arm/lithium-arm.cc
+@@ -1195,7 +1195,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
+
+ LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
+ LOperand* context = UseRegisterAtStart(instr->value());
+- return DefineAsRegister(new LGlobalObject(context));
++ return DefineAsRegister(new LGlobalObject(context, instr->qml_global()));
+ }
+
+
+diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
+index 6da7c86..10b901f 100644
+--- a/src/arm/lithium-arm.h
++++ b/src/arm/lithium-arm.h
+@@ -1378,13 +1378,17 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
+
+ class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
+ public:
+- explicit LGlobalObject(LOperand* context) {
++ explicit LGlobalObject(LOperand* context, bool qml_global) {
+ inputs_[0] = context;
++ qml_global_ = qml_global;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
+
+ LOperand* context() { return InputAt(0); }
++ bool qml_global() { return qml_global_; }
++ private:
++ bool qml_global_;
+ };
+
+
+diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
+index 4912449..db114ea 100644
+--- a/src/arm/lithium-codegen-arm.cc
++++ b/src/arm/lithium-codegen-arm.cc
+@@ -166,12 +166,13 @@ bool LCodeGen::GeneratePrologue() {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment(";;; Allocate local context");
+ // Argument to NewContext is the function, which is in r1.
+ __ push(r1);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -2664,7 +2665,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
+ void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
+ Register context = ToRegister(instr->context());
+ Register result = ToRegister(instr->result());
+- __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
++ __ ldr(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX));
+ }
+
+
+diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
+index ab5efb0..d40cdbc 100644
+--- a/src/arm/macro-assembler-arm.h
++++ b/src/arm/macro-assembler-arm.h
+@@ -1056,6 +1056,11 @@ static inline MemOperand GlobalObjectOperand() {
+ }
+
+
++static inline MemOperand QmlGlobalObjectOperand() {
++ return ContextOperand(cp, Context::QML_GLOBAL_INDEX);
++}
++
++
+ #ifdef GENERATED_CODE_COVERAGE
+ #define CODE_COVERAGE_STRINGIFY(x) #x
+ #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
+diff --git a/src/ast-inl.h b/src/ast-inl.h
+index d80684a..adc5a1f 100644
+--- a/src/ast-inl.h
++++ b/src/ast-inl.h
+@@ -106,6 +106,11 @@ bool FunctionLiteral::strict_mode() const {
+ }
+
+
++bool FunctionLiteral::qml_mode() const {
++ return scope()->is_qml_mode();
++}
++
++
+ } } // namespace v8::internal
+
+ #endif // V8_AST_INL_H_
+diff --git a/src/ast.h b/src/ast.h
+index 65a25a9..f790dc0 100644
+--- a/src/ast.h
++++ b/src/ast.h
+@@ -1712,6 +1712,7 @@ class FunctionLiteral: public Expression {
+ int end_position() const { return end_position_; }
+ bool is_expression() const { return is_expression_; }
+ bool strict_mode() const;
++ bool qml_mode() const;
+
+ int materialized_literal_count() { return materialized_literal_count_; }
+ int expected_property_count() { return expected_property_count_; }
+diff --git a/src/code-stubs.h b/src/code-stubs.h
+index 56ef072..37e5383 100644
+--- a/src/code-stubs.h
++++ b/src/code-stubs.h
+@@ -303,7 +303,7 @@ class FastNewContextStub : public CodeStub {
+ static const int kMaximumSlots = 64;
+
+ explicit FastNewContextStub(int slots) : slots_(slots) {
+- ASSERT(slots_ > 0 && slots <= kMaximumSlots);
++ ASSERT(slots_ >= 0 && slots <= kMaximumSlots);
+ }
+
+ void Generate(MacroAssembler* masm);
+diff --git a/src/compiler.cc b/src/compiler.cc
+index 86d5de3..d2191b9 100755
+--- a/src/compiler.cc
++++ b/src/compiler.cc
+@@ -462,7 +462,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ v8::Extension* extension,
+ ScriptDataImpl* input_pre_data,
+ Handle<Object> script_data,
+- NativesFlag natives) {
++ NativesFlag natives,
++ v8::Script::CompileFlags compile_flags) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_load_size()->Increment(source_length);
+@@ -523,6 +524,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ info.MarkAsGlobal();
+ info.SetExtension(extension);
+ info.SetPreParseData(pre_data);
++ if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode();
+ if (natives == NATIVES_CODE) info.MarkAsAllowingNativesSyntax();
+ result = MakeFunctionInfo(&info);
+ if (extension == NULL && !result.is_null()) {
+@@ -543,7 +545,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_eval_size()->Increment(source_length);
+@@ -567,6 +570,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
+ CompilationInfo info(script);
+ info.MarkAsEval();
+ if (is_global) info.MarkAsGlobal();
++ if (qml_mode) info.MarkAsQmlMode();
+ if (strict_mode == kStrictMode) info.MarkAsStrictMode();
+ info.SetCallingContext(context);
+ result = MakeFunctionInfo(&info);
+@@ -610,6 +614,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
+ info->MarkAsStrictMode();
+ }
+
++ // After parsing we know function's qml mode. Remember it.
++ if (info->function()->qml_mode()) {
++ shared->set_qml_mode(true);
++ info->MarkAsQmlMode();
++ }
++
+ // Compile the code.
+ if (!MakeCode(info)) {
+ if (!isolate->has_pending_exception()) {
+@@ -755,6 +765,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
+ *lit->this_property_assignments());
+ function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
+ function_info->set_strict_mode(lit->strict_mode());
++ function_info->set_qml_mode(lit->qml_mode());
+ }
+
+
+diff --git a/src/compiler.h b/src/compiler.h
+index e75e869..17cd369 100644
+--- a/src/compiler.h
++++ b/src/compiler.h
+@@ -54,6 +54,7 @@ class CompilationInfo BASE_EMBEDDED {
+ bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
+ bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; }
+ bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
++ bool is_qml_mode() const { return (flags_ & IsQmlMode::mask()) != 0; }
+ FunctionLiteral* function() const { return function_; }
+ Scope* scope() const { return scope_; }
+ Handle<Code> code() const { return code_; }
+@@ -83,6 +84,9 @@ class CompilationInfo BASE_EMBEDDED {
+ ASSERT(is_lazy());
+ flags_ |= IsInLoop::encode(true);
+ }
++ void MarkAsQmlMode() {
++ flags_ |= IsQmlMode::encode(true);
++ }
+ void MarkAsAllowingNativesSyntax() {
+ flags_ |= IsNativesSyntaxAllowed::encode(true);
+ }
+@@ -141,6 +145,7 @@ class CompilationInfo BASE_EMBEDDED {
+
+ // Determine whether or not we can adaptively optimize.
+ bool AllowOptimize() {
++ // XXX - fix qml mode optimizations
+ return V8::UseCrankshaft() && !closure_.is_null();
+ }
+
+@@ -163,8 +168,13 @@ class CompilationInfo BASE_EMBEDDED {
+
+ void Initialize(Mode mode) {
+ mode_ = V8::UseCrankshaft() ? mode : NONOPT;
+- if (!shared_info_.is_null() && shared_info_->strict_mode()) {
+- MarkAsStrictMode();
++ if (!shared_info_.is_null()) {
++ if (shared_info_->strict_mode()) {
++ MarkAsStrictMode();
++ }
++ if (shared_info_->qml_mode()) {
++ MarkAsQmlMode();
++ }
+ }
+ }
+
+@@ -187,6 +197,8 @@ class CompilationInfo BASE_EMBEDDED {
+ class IsStrictMode: public BitField<bool, 4, 1> {};
+ // Native syntax (%-stuff) allowed?
+ class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {};
++ // Qml mode
++ class IsQmlMode: public BitField<bool, 6, 1> {};
+
+ unsigned flags_;
+
+@@ -252,13 +264,15 @@ class Compiler : public AllStatic {
+ v8::Extension* extension,
+ ScriptDataImpl* pre_data,
+ Handle<Object> script_data,
+- NativesFlag is_natives_code);
++ NativesFlag is_natives_code,
++ v8::Script::CompileFlags compile_flags = v8::Script::Default);
+
+ // Compile a String source within a context for Eval.
+ static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool qml_mode);
+
+ // Compile from function info (used for lazy compilation). Returns true on
+ // success and false if the compilation resulted in a stack overflow.
+diff --git a/src/contexts.cc b/src/contexts.cc
+index 520f3dd..da5cacb 100644
+--- a/src/contexts.cc
++++ b/src/contexts.cc
+@@ -89,6 +89,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ PrintF(")\n");
+ }
+
++ Handle<JSObject> qml_global;
++
+ do {
+ if (FLAG_trace_contexts) {
+ PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
+@@ -119,6 +121,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ }
+ }
+
++ if (qml_global.is_null() && !context->qml_global()->IsUndefined()) {
++ qml_global = Handle<JSObject>(context->qml_global(), isolate);
++ }
++
+ if (context->is_function_context()) {
+ // we have context-local slots
+
+@@ -198,6 +204,23 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ }
+ } while (follow_context_chain);
+
++ if (!qml_global.is_null()) {
++ if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
++ *attributes = qml_global->GetLocalPropertyAttribute(*name);
++ } else {
++ *attributes = qml_global->GetPropertyAttribute(*name);
++ }
++
++ if (*attributes != ABSENT) {
++ // property found
++ if (FLAG_trace_contexts) {
++ PrintF("=> found property in qml global object %p\n",
++ reinterpret_cast<void*>(*qml_global));
++ }
++ return qml_global;
++ }
++ }
++
+ // slot not found
+ if (FLAG_trace_contexts) {
+ PrintF("=> no property/slot found\n");
+diff --git a/src/contexts.h b/src/contexts.h
+index e46619e..57d8e7b 100644
+--- a/src/contexts.h
++++ b/src/contexts.h
+@@ -182,6 +182,7 @@ class Context: public FixedArray {
+ FCONTEXT_INDEX,
+ PREVIOUS_INDEX,
+ EXTENSION_INDEX,
++ QML_GLOBAL_INDEX,
+ GLOBAL_INDEX,
+ MIN_CONTEXT_SLOTS,
+
+@@ -273,6 +274,9 @@ class Context: public FixedArray {
+ }
+ void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
+
++ JSObject *qml_global() { return reinterpret_cast<JSObject *>(get(QML_GLOBAL_INDEX)); }
++ void set_qml_global(JSObject *qml_global) { set(QML_GLOBAL_INDEX, qml_global); }
++
+ // Returns a JSGlobalProxy object or null.
+ JSObject* global_proxy();
+ void set_global_proxy(JSObject* global);
+diff --git a/src/execution.cc b/src/execution.cc
+index eb26438..1632076 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -70,7 +70,8 @@ static Handle<Object> Invoke(bool construct,
+ Handle<Object> receiver,
+ int argc,
+ Object*** args,
+- bool* has_pending_exception) {
++ bool* has_pending_exception,
++ Handle<Object> qml) {
+ Isolate* isolate = func->GetIsolate();
+
+ // Entering JavaScript.
+@@ -107,6 +108,12 @@ static Handle<Object> Invoke(bool construct,
+ // make the current one is indeed a global object.
+ ASSERT(func->context()->global()->IsGlobalObject());
+
++ Handle<JSObject> oldqml;
++ if (!qml.is_null()) {
++ oldqml = Handle<JSObject>(func->context()->qml_global());
++ func->context()->set_qml_global(JSObject::cast(*qml));
++ }
++
+ {
+ // Save and restore context around invocation and block the
+ // allocation of handles without explicit handle scopes.
+@@ -122,6 +129,9 @@ static Handle<Object> Invoke(bool construct,
+ receiver_pointer, argc, args);
+ }
+
++ if (!qml.is_null())
++ func->context()->set_qml_global(*oldqml);
++
+ #ifdef DEBUG
+ value->Verify();
+ #endif
+@@ -150,14 +160,24 @@ Handle<Object> Execution::Call(Handle<JSFunction> func,
+ int argc,
+ Object*** args,
+ bool* pending_exception) {
+- return Invoke(false, func, receiver, argc, args, pending_exception);
++ return Invoke(false, func, receiver, argc, args, pending_exception, Handle<Object>());
++}
++
++
++Handle<Object> Execution::Call(Handle<JSFunction> func,
++ Handle<Object> receiver,
++ int argc,
++ Object*** args,
++ bool* pending_exception,
++ Handle<Object> qml) {
++ return Invoke(false, func, receiver, argc, args, pending_exception, qml);
+ }
+
+
+ Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
+ Object*** args, bool* pending_exception) {
+ return Invoke(true, func, Isolate::Current()->global(), argc, args,
+- pending_exception);
++ pending_exception, Handle<Object>());
+ }
+
+
+@@ -175,7 +195,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
+ catcher.SetCaptureMessage(false);
+
+ Handle<Object> result = Invoke(false, func, receiver, argc, args,
+- caught_exception);
++ caught_exception, Handle<Object>());
+
+ if (*caught_exception) {
+ ASSERT(catcher.HasCaught());
+diff --git a/src/execution.h b/src/execution.h
+index d4b80d2..a476eb4 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -56,6 +56,12 @@ class Execution : public AllStatic {
+ int argc,
+ Object*** args,
+ bool* pending_exception);
++ static Handle<Object> Call(Handle<JSFunction> func,
++ Handle<Object> receiver,
++ int argc,
++ Object*** args,
++ bool* pending_exception,
++ Handle<Object> qml);
+
+ // Construct object from function, the caller supplies an array of
+ // arguments. Arguments are Object* type. After function returns,
+diff --git a/src/full-codegen.cc b/src/full-codegen.cc
+index d6ba56e..2eaef0f 100644
+--- a/src/full-codegen.cc
++++ b/src/full-codegen.cc
+@@ -542,7 +542,7 @@ void FullCodeGenerator::VisitDeclarations(
+ // Do nothing in case of no declared global functions or variables.
+ if (globals > 0) {
+ Handle<FixedArray> array =
+- isolate()->factory()->NewFixedArray(2 * globals, TENURED);
++ isolate()->factory()->NewFixedArray(3 * globals, TENURED);
+ for (int j = 0, i = 0; i < length; i++) {
+ Declaration* decl = declarations->at(i);
+ Variable* var = decl->proxy()->var();
+@@ -567,6 +567,7 @@ void FullCodeGenerator::VisitDeclarations(
+ }
+ array->set(j++, *function);
+ }
++ array->set(j++, Smi::FromInt(var->is_qml_global()));
+ }
+ }
+ // Invoke the platform-dependent code generator to do the actual
+diff --git a/src/full-codegen.h b/src/full-codegen.h
+index d6ed1b9..e3241aa 100644
+--- a/src/full-codegen.h
++++ b/src/full-codegen.h
+@@ -505,6 +505,7 @@ class FullCodeGenerator: public AstVisitor {
+ StrictModeFlag strict_mode_flag() {
+ return is_strict_mode() ? kStrictMode : kNonStrictMode;
+ }
++ bool is_qml_mode() { return function()->qml_mode(); }
+ FunctionLiteral* function() { return info_->function(); }
+ Scope* scope() { return info_->scope(); }
+
+diff --git a/src/heap.cc b/src/heap.cc
+index bf2940e..da958c2 100644
+--- a/src/heap.cc
++++ b/src/heap.cc
+@@ -3795,6 +3795,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
+ context->set_previous(NULL);
+ context->set_extension(NULL);
+ context->set_global(function->context()->global());
++ context->set_qml_global(function->context()->qml_global());
+ ASSERT(!context->IsGlobalContext());
+ ASSERT(context->is_function_context());
+ ASSERT(result->IsContext());
+@@ -3817,6 +3818,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
+ context->set_previous(previous);
+ context->set_extension(extension);
+ context->set_global(previous->global());
++ context->set_qml_global(previous->qml_global());
+ ASSERT(!context->IsGlobalContext());
+ ASSERT(!context->is_function_context());
+ ASSERT(result->IsContext());
+diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
+index a623775..52455bc 100644
+--- a/src/hydrogen-instructions.h
++++ b/src/hydrogen-instructions.h
+@@ -1148,7 +1148,7 @@ class HOuterContext: public HUnaryOperation {
+
+ class HGlobalObject: public HUnaryOperation {
+ public:
+- explicit HGlobalObject(HValue* context) : HUnaryOperation(context) {
++ explicit HGlobalObject(HValue* context) : HUnaryOperation(context), qml_global_(false) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+@@ -1159,8 +1159,14 @@ class HGlobalObject: public HUnaryOperation {
+ return Representation::Tagged();
+ }
+
++ bool qml_global() { return qml_global_; }
++ void set_qml_global(bool v) { qml_global_ = v; }
++
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
++
++ private:
++ bool qml_global_;
+ };
+
+
+@@ -1177,7 +1183,7 @@ class HGlobalReceiver: public HUnaryOperation {
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+-
++
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+ };
+diff --git a/src/hydrogen.cc b/src/hydrogen.cc
+index 73ea97d..d17e304 100644
+--- a/src/hydrogen.cc
++++ b/src/hydrogen.cc
+@@ -2918,6 +2918,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
+ HContext* context = new(zone()) HContext;
+ AddInstruction(context);
+ HGlobalObject* global_object = new(zone()) HGlobalObject(context);
++ if (variable->is_qml_global()) global_object->set_qml_global(true);
+ AddInstruction(global_object);
+ HLoadGlobalGeneric* instr =
+ new(zone()) HLoadGlobalGeneric(context,
+@@ -3307,6 +3308,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
+ HContext* context = new(zone()) HContext;
+ AddInstruction(context);
+ HGlobalObject* global_object = new(zone()) HGlobalObject(context);
++ if (var->is_qml_global()) global_object->set_qml_global(true);
+ AddInstruction(global_object);
+ HStoreGlobalGeneric* instr =
+ new(zone()) HStoreGlobalGeneric(context,
+diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
+index 5d32095..afa599e 100644
+--- a/src/ia32/code-stubs-ia32.cc
++++ b/src/ia32/code-stubs-ia32.cc
+@@ -147,6 +147,13 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
+ __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
+
++ // Copy the qml global object from the surrounding context. We go through the
++ // context in the function (ecx) to match the allocation behavior we have
++ // in the runtime system (see Heap::AllocateFunctionContext).
++ __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset));
++ __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++ __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), ebx);
++
+ // Initialize the rest of the slots to undefined.
+ __ mov(ebx, factory->undefined_value());
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
+diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
+index 5d153a8..0ddcde2 100644
+--- a/src/ia32/full-codegen-ia32.cc
++++ b/src/ia32/full-codegen-ia32.cc
+@@ -142,12 +142,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment cmnt(masm_, "[ Allocate local context");
+ // Argument to NewContext is the function, which is still in edi.
+ __ push(edi);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -1107,10 +1108,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+
+ // All extension objects were empty and it is safe to use a global
+ // load IC call.
+- __ mov(eax, GlobalObjectOperand());
++ __ mov(eax, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(ecx, slot->var()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global())
+ ? RelocInfo::CODE_TARGET
+ : RelocInfo::CODE_TARGET_CONTEXT;
+ EmitCallIC(ic, mode);
+@@ -1214,10 +1215,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in ecx and the global
+ // object on the stack.
+- __ mov(eax, GlobalObjectOperand());
++ __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(ecx, var->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(eax);
+
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+@@ -1837,11 +1838,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+ // assignment. Right-hand-side value is passed in eax, variable name in
+ // ecx, and the global object on the stack.
+ __ mov(ecx, var->name());
+- __ mov(edx, GlobalObjectOperand());
++ __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (op == Token::INIT_CONST) {
+ // Like var declarations, const declarations are hoisted to function
+@@ -2113,9 +2114,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
+ // Push the strict mode flag.
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+
++ // Push the qml mode flag
++ __ push(Immediate(Smi::FromInt(is_qml_mode())));
++
+ __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
+ ? Runtime::kResolvePossiblyDirectEvalNoLookup
+- : Runtime::kResolvePossiblyDirectEval, 4);
++ : Runtime::kResolvePossiblyDirectEval, 5);
+ }
+
+
+@@ -2188,8 +2192,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
+ context()->DropAndPlug(1, eax);
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Push global object as receiver for the call IC.
+- __ push(GlobalObjectOperand());
+- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
++ __ push(var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (var != NULL && var->AsSlot() != NULL &&
+ var->AsSlot()->type() == Slot::LOOKUP) {
+ // Call to a lookup slot (dynamically introduced variable).
+diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
+index 0f96f78..c1da075 100644
+--- a/src/ia32/lithium-codegen-ia32.cc
++++ b/src/ia32/lithium-codegen-ia32.cc
+@@ -159,12 +159,13 @@ bool LCodeGen::GeneratePrologue() {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment(";;; Allocate local context");
+ // Argument to NewContext is the function, which is still in edi.
+ __ push(edi);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -2525,7 +2526,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
+ void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
+ Register context = ToRegister(instr->context());
+ Register result = ToRegister(instr->result());
+- __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
++ __ mov(result, Operand(context, Context::SlotOffset(instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)));
+ }
+
+
+diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
+index 9ccd189..8e98b73 100644
+--- a/src/ia32/lithium-ia32.cc
++++ b/src/ia32/lithium-ia32.cc
+@@ -1205,7 +1205,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
+
+ LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
+ LOperand* context = UseRegisterAtStart(instr->value());
+- return DefineAsRegister(new LGlobalObject(context));
++ return DefineAsRegister(new LGlobalObject(context, instr->qml_global()));
+ }
+
+
+diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
+index 9ace8f8..95ed001 100644
+--- a/src/ia32/lithium-ia32.h
++++ b/src/ia32/lithium-ia32.h
+@@ -1416,13 +1416,17 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
+
+ class LGlobalObject: public LTemplateInstruction<1, 1, 0> {
+ public:
+- explicit LGlobalObject(LOperand* context) {
++ explicit LGlobalObject(LOperand* context, bool qml_global) {
+ inputs_[0] = context;
++ qml_global_ = qml_global;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
+
+ LOperand* context() { return InputAt(0); }
++ bool qml_global() { return qml_global_; }
++ private:
++ bool qml_global_;
+ };
+
+
+diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
+index b986264..f8479ae 100644
+--- a/src/ia32/macro-assembler-ia32.h
++++ b/src/ia32/macro-assembler-ia32.h
+@@ -778,6 +778,11 @@ static inline Operand GlobalObjectOperand() {
+ }
+
+
++static inline Operand QmlGlobalObjectOperand() {
++ return ContextOperand(esi, Context::QML_GLOBAL_INDEX);
++}
++
++
+ // Generates an Operand for saving parameters after PrepareCallApiFunction.
+ Operand ApiParameterOperand(int index);
+
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 231b835..1c7f83e 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -3242,6 +3242,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) {
+ }
+
+
++bool SharedFunctionInfo::qml_mode() {
++ return BooleanBit::get(compiler_hints(), kQmlModeFunction);
++}
++
++
++void SharedFunctionInfo::set_qml_mode(bool value) {
++ set_compiler_hints(BooleanBit::set(compiler_hints(),
++ kQmlModeFunction,
++ value));
++}
++
++
+ ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
+ ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
+
+diff --git a/src/objects.h b/src/objects.h
+index 1bdb5c7..edbc47a 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -4331,6 +4331,10 @@ class SharedFunctionInfo: public HeapObject {
+ inline bool strict_mode();
+ inline void set_strict_mode(bool value);
+
++ // Indicates whether the function is a qml mode function
++ inline bool qml_mode();
++ inline void set_qml_mode(bool value);
++
+ // Indicates whether or not the code in the shared function support
+ // deoptimization.
+ inline bool has_deoptimization_support();
+@@ -4511,6 +4515,7 @@ class SharedFunctionInfo: public HeapObject {
+ static const int kCodeAgeMask = 0x7;
+ static const int kOptimizationDisabled = 6;
+ static const int kStrictModeFunction = 7;
++ static const int kQmlModeFunction = 8;
+
+ private:
+ #if V8_HOST_ARCH_32_BIT
+diff --git a/src/parser.cc b/src/parser.cc
+index a84ec6f..7f5c361 100644
+--- a/src/parser.cc
++++ b/src/parser.cc
+@@ -593,7 +593,8 @@ Parser::Parser(Handle<Script> script,
+
+ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ bool in_global_context,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
+
+ HistogramTimerScope timer(isolate()->counters()->parse());
+@@ -609,11 +610,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ ExternalTwoByteStringUC16CharacterStream stream(
+ Handle<ExternalTwoByteString>::cast(source), 0, source->length());
+ scanner_.Initialize(&stream);
+- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope);
+ } else {
+ GenericStringUC16CharacterStream stream(source, 0, source->length());
+ scanner_.Initialize(&stream);
+- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope);
+ }
+ }
+
+@@ -621,6 +622,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
+ bool in_global_context,
+ StrictModeFlag strict_mode,
++ bool qml_mode,
+ ZoneScope* zone_scope) {
+ ASSERT(target_stack_ == NULL);
+ if (pre_data_ != NULL) pre_data_->Initialize();
+@@ -641,6 +643,9 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
+ if (strict_mode == kStrictMode) {
+ top_scope_->EnableStrictMode();
+ }
++ if (qml_mode) {
++ scope->EnableQmlMode();
++ }
+ ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
+ bool ok = true;
+ int beg_loc = scanner().location().beg_pos;
+@@ -729,6 +734,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
+ if (shared_info->strict_mode()) {
+ top_scope_->EnableStrictMode();
+ }
++ if (shared_info->qml_mode()) {
++ top_scope_->EnableQmlMode();
++ }
+
+ FunctionLiteralType type =
+ shared_info->is_expression() ? EXPRESSION : DECLARATION;
+@@ -1661,6 +1669,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
+ arguments->Add(value);
+ value = NULL; // zap the value to avoid the unnecessary assignment
+
++ int qml_mode = 0;
++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
++ qml_mode = 1;
++ arguments->Add(NewNumberLiteral(qml_mode));
++
+ // Construct the call to Runtime_InitializeConstGlobal
+ // and add it to the initialization statement block.
+ // Note that the function does different things depending on
+@@ -1676,6 +1689,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
+ arguments->Add(NewNumberLiteral(
+ top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
+
++ int qml_mode = 0;
++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
++ qml_mode = 1;
++ arguments->Add(NewNumberLiteral(qml_mode));
++
+ // Be careful not to assign a value to the global variable if
+ // we're in a with. The initialization value should not
+ // necessarily be stored in the global object in that case,
+@@ -5157,7 +5175,8 @@ bool ParserApi::Parse(CompilationInfo* info) {
+ Handle<String> source = Handle<String>(String::cast(script->source()));
+ result = parser.ParseProgram(source,
+ info->is_global(),
+- info->StrictMode());
++ info->StrictMode(),
++ info->is_qml_mode());
+ }
+ }
+
+diff --git a/src/parser.h b/src/parser.h
+index 64f1303..4d45e45 100644
+--- a/src/parser.h
++++ b/src/parser.h
+@@ -431,7 +431,8 @@ class Parser {
+ // Returns NULL if parsing failed.
+ FunctionLiteral* ParseProgram(Handle<String> source,
+ bool in_global_context,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool qml_mode);
+
+ FunctionLiteral* ParseLazy(CompilationInfo* info);
+
+@@ -464,6 +465,7 @@ class Parser {
+ FunctionLiteral* DoParseProgram(Handle<String> source,
+ bool in_global_context,
+ StrictModeFlag strict_mode,
++ bool qml_mode,
+ ZoneScope* zone_scope);
+
+ // Report syntax error
+diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
+index c777ab4..1964e02 100644
+--- a/src/prettyprinter.cc
++++ b/src/prettyprinter.cc
+@@ -656,6 +656,9 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
+ EmbeddedVector<char, 256> buf;
+ int pos = OS::SNPrintF(buf, "%s (mode = %s", info,
+ Variable::Mode2String(var->mode()));
++ if (var->is_qml_global()) {
++ pos += OS::SNPrintF(buf + pos, ":QML");
++ }
+ OS::SNPrintF(buf + pos, ")");
+ PrintLiteralIndented(buf.start(), value, true);
+ }
+diff --git a/src/runtime.cc b/src/runtime.cc
+index 660352c..827d954 100644
+--- a/src/runtime.cc
++++ b/src/runtime.cc
+@@ -1065,8 +1065,6 @@ static Failure* ThrowRedeclarationError(Isolate* isolate,
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ ASSERT(args.length() == 4);
+ HandleScope scope(isolate);
+- Handle<GlobalObject> global = Handle<GlobalObject>(
+- isolate->context()->global());
+
+ Handle<Context> context = args.at<Context>(0);
+ CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
+@@ -1075,6 +1073,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
+
++ Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global());
++ Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global());
++
+ // Compute the property attributes. According to ECMA-262, section
+ // 13, page 71, the property must be read-only and
+ // non-deletable. However, neither SpiderMonkey nor KJS creates the
+@@ -1083,10 +1084,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+
+ // Traverse the name/value pairs and set the properties.
+ int length = pairs->length();
+- for (int i = 0; i < length; i += 2) {
++ for (int i = 0; i < length; i += 3) {
+ HandleScope scope(isolate);
+ Handle<String> name(String::cast(pairs->get(i)));
+ Handle<Object> value(pairs->get(i + 1), isolate);
++ Handle<Smi> is_qml_global(Smi::cast(pairs->get(i + 2)));
++
++ Handle<JSObject> global = is_qml_global->value()?qml_global:js_global;
+
+ // We have to declare a global const property. To capture we only
+ // assign to it when evaluating the assignment for "const x =
+@@ -1316,20 +1320,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ NoHandleAllocation nha;
+ // args[0] == name
+ // args[1] == strict_mode
+- // args[2] == value (optional)
++ // args[2] == qml_mode
++ // args[3] == value (optional)
+
+ // Determine if we need to assign to the variable if it already
+ // exists (based on the number of arguments).
+- RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
+- bool assign = args.length() == 3;
++ RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
++ bool assign = args.length() == 4;
+
+ CONVERT_ARG_CHECKED(String, name, 0);
+- GlobalObject* global = isolate->context()->global();
+ RUNTIME_ASSERT(args[1]->IsSmi());
+ StrictModeFlag strict_mode =
+ static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
+
++ RUNTIME_ASSERT(args[2]->IsSmi());
++ int qml_mode = Smi::cast(args[2])->value();
++
++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
++
+ // According to ECMA-262, section 12.2, page 62, the property must
+ // not be deletable.
+ PropertyAttributes attributes = DONT_DELETE;
+@@ -1350,7 +1359,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ if (lookup.IsReadOnly()) {
+ // If we found readonly property on one of hidden prototypes,
+ // just shadow it.
+- if (real_holder != isolate->context()->global()) break;
++ if (real_holder != global) break;
+ return ThrowRedeclarationError(isolate, "const", name);
+ }
+
+@@ -1372,7 +1381,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ // overwrite it with a variable declaration we must throw a
+ // re-declaration error. However if we found readonly property
+ // on one of hidden prototypes, just shadow it.
+- if (real_holder != isolate->context()->global()) break;
++ if (real_holder != global) break;
+ return ThrowRedeclarationError(isolate, "const", name);
+ }
+ }
+@@ -1384,7 +1393,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ }
+
+ // Assign the value (or undefined) to the property.
+- Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
++ Object* value = (assign) ? args[3] : isolate->heap()->undefined_value();
+ return real_holder->SetProperty(
+ &lookup, *name, value, attributes, strict_mode);
+ }
+@@ -1399,9 +1408,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ real_holder = JSObject::cast(proto);
+ }
+
+- global = isolate->context()->global();
++ global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+ if (assign) {
+- return global->SetProperty(*name, args[2], attributes, strict_mode, true);
++ return global->SetProperty(*name, args[3], attributes, strict_mode, true);
+ }
+ return isolate->heap()->undefined_value();
+ }
+@@ -1411,12 +1420,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
+ // All constants are declared with an initial value. The name
+ // of the constant is the first argument and the initial value
+ // is the second.
+- RUNTIME_ASSERT(args.length() == 2);
++ RUNTIME_ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(String, name, 0);
+ Handle<Object> value = args.at<Object>(1);
+
++ RUNTIME_ASSERT(args[2]->IsSmi());
++ int qml_mode = Smi::cast(args[2])->value();
++
+ // Get the current global object from top.
+- GlobalObject* global = isolate->context()->global();
++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+
+ // According to ECMA-262, section 12.2, page 62, the property must
+ // not be deletable. Since it's a const, it must be READ_ONLY too.
+@@ -1456,7 +1468,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
+ // with setting the value because the property is either absent or
+ // read-only. We also have to do redo the lookup.
+ HandleScope handle_scope(isolate);
+- Handle<GlobalObject> global(isolate->context()->global());
++ Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global());
+
+ // BUG 1213575: Handle the case where we have to set a read-only
+ // property through an interceptor and only do it if it's
+@@ -8160,7 +8172,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
+ Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
+ context,
+ true,
+- kNonStrictMode);
++ kNonStrictMode,
++ false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> fun =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+@@ -8173,14 +8186,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
+ static ObjectPair CompileGlobalEval(Isolate* isolate,
+ Handle<String> source,
+ Handle<Object> receiver,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ // Deal with a normal eval call with a string argument. Compile it
+ // and return the compiled function bound in the local context.
+ Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
+ source,
+ Handle<Context>(isolate->context()),
+ isolate->context()->IsGlobalContext(),
+- strict_mode);
++ strict_mode,
++ qml_mode);
+ if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
+ Handle<JSFunction> compiled =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+@@ -8190,7 +8205,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
+
+
+ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
+- ASSERT(args.length() == 4);
++ ASSERT(args.length() == 5);
+
+ HandleScope scope(isolate);
+ Handle<Object> callee = args.at<Object>(0);
+@@ -8257,16 +8272,18 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
+ }
+
+ ASSERT(args[3]->IsSmi());
++ ASSERT(args[4]->IsSmi());
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+- Smi::cast(args[3])->value()));
++ Smi::cast(args[3])->value()),
++ Smi::cast(args[4])->value());
+ }
+
+
+ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
+- ASSERT(args.length() == 4);
++ ASSERT(args.length() == 5);
+
+ HandleScope scope(isolate);
+ Handle<Object> callee = args.at<Object>(0);
+@@ -8280,11 +8297,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
+ }
+
+ ASSERT(args[3]->IsSmi());
++ ASSERT(args[4]->IsSmi());
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+- Smi::cast(args[3])->value()));
++ Smi::cast(args[3])->value()),
++ Smi::cast(args[4])->value());
+ }
+
+
+@@ -10633,7 +10652,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
+ Compiler::CompileEval(function_source,
+ context,
+ context->IsGlobalContext(),
+- kNonStrictMode);
++ kNonStrictMode,
++ false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> compiled_function =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
+@@ -10722,7 +10742,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
+ // Currently, the eval code will be executed in non-strict mode,
+ // even in the strict code context.
+ Handle<SharedFunctionInfo> shared =
+- Compiler::CompileEval(source, context, is_global, kNonStrictMode);
++ Compiler::CompileEval(source, context, is_global, kNonStrictMode, false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> compiled_function =
+ Handle<JSFunction>(
+diff --git a/src/runtime.h b/src/runtime.h
+index bf1ba68..5e97173 100644
+--- a/src/runtime.h
++++ b/src/runtime.h
+@@ -241,8 +241,8 @@ namespace internal {
+ \
+ /* Eval */ \
+ F(GlobalReceiver, 1, 1) \
+- F(ResolvePossiblyDirectEval, 4, 2) \
+- F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \
++ F(ResolvePossiblyDirectEval, 5, 2) \
++ F(ResolvePossiblyDirectEvalNoLookup, 5, 2) \
+ \
+ F(SetProperty, -1 /* 4 or 5 */, 1) \
+ F(DefineOrRedefineDataProperty, 4, 1) \
+@@ -296,8 +296,8 @@ namespace internal {
+ /* Declarations and initialization */ \
+ F(DeclareGlobals, 4, 1) \
+ F(DeclareContextSlot, 4, 1) \
+- F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
+- F(InitializeConstGlobal, 2, 1) \
++ F(InitializeVarGlobal, -1 /* 3 or 4 */, 1) \
++ F(InitializeConstGlobal, 3, 1) \
+ F(InitializeConstContextSlot, 3, 1) \
+ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
+ \
+diff --git a/src/scopes.cc b/src/scopes.cc
+index 8df93c5..734a217 100644
+--- a/src/scopes.cc
++++ b/src/scopes.cc
+@@ -198,6 +198,7 @@ void Scope::SetDefaults(Type type,
+ scope_calls_eval_ = false;
+ // Inherit the strict mode from the parent scope.
+ strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
++ qml_mode_ = (outer_scope != NULL) && outer_scope->qml_mode_;
+ outer_scope_calls_eval_ = false;
+ inner_scope_calls_eval_ = false;
+ outer_scope_is_eval_scope_ = false;
+@@ -796,6 +797,10 @@ void Scope::ResolveVariable(Scope* global_scope,
+ ASSERT(global_scope != NULL);
+ var = global_scope->DeclareGlobal(proxy->name());
+
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) {
++ var->set_is_qml_global(true);
++ }
++
+ } else if (scope_inside_with_) {
+ // If we are inside a with statement we give up and look up
+ // the variable at runtime.
+@@ -816,6 +821,8 @@ void Scope::ResolveVariable(Scope* global_scope,
+ // variables.
+ if (context->GlobalIfNotShadowedByEval(proxy->name())) {
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name())))
++ var->set_is_qml_global(true);
+
+ } else {
+ var = NonLocal(proxy->name(), Variable::DYNAMIC);
+@@ -827,6 +834,9 @@ void Scope::ResolveVariable(Scope* global_scope,
+ // variable is global unless it is shadowed by eval-introduced
+ // variables.
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
++
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name())))
++ var->set_is_qml_global(true);
+ }
+ }
+ }
+diff --git a/src/scopes.h b/src/scopes.h
+index a0e56a4..6dd3f65 100644
+--- a/src/scopes.h
++++ b/src/scopes.h
+@@ -210,6 +210,11 @@ class Scope: public ZoneObject {
+ strict_mode_ = FLAG_strict_mode;
+ }
+
++ // Enable qml mode for this scope
++ void EnableQmlMode() {
++ qml_mode_ = true;
++ }
++
+ // ---------------------------------------------------------------------------
+ // Predicates.
+
+@@ -218,6 +223,7 @@ class Scope: public ZoneObject {
+ bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
+ bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
+ bool is_strict_mode() const { return strict_mode_; }
++ bool is_qml_mode() const { return qml_mode_; }
+
+ // Information about which scopes calls eval.
+ bool calls_eval() const { return scope_calls_eval_; }
+@@ -376,6 +382,7 @@ class Scope: public ZoneObject {
+ bool scope_contains_with_; // this scope contains a 'with' statement
+ bool scope_calls_eval_; // this scope contains an 'eval' call
+ bool strict_mode_; // this scope is a strict mode scope
++ bool qml_mode_; // this scope is a qml mode scope
+
+ // Computed via PropagateScopeInfo.
+ bool outer_scope_calls_eval_;
+diff --git a/src/variables.cc b/src/variables.cc
+index 0502722..190baf6 100644
+--- a/src/variables.cc
++++ b/src/variables.cc
+@@ -99,7 +99,8 @@ Variable::Variable(Scope* scope,
+ rewrite_(NULL),
+ is_valid_LHS_(is_valid_LHS),
+ is_accessed_from_inner_scope_(false),
+- is_used_(false) {
++ is_used_(false),
++ is_qml_global_(false) {
+ // names must be canonicalized for fast equality checks
+ ASSERT(name->IsSymbol());
+ }
+diff --git a/src/variables.h b/src/variables.h
+index b1ff0db..0b31d1a 100644
+--- a/src/variables.h
++++ b/src/variables.h
+@@ -141,6 +141,8 @@ class Variable: public ZoneObject {
+ Expression* rewrite() const { return rewrite_; }
+ void set_rewrite(Expression* expr) { rewrite_ = expr; }
+
++ bool is_qml_global() const { return is_qml_global_; }
++ void set_is_qml_global(bool is_qml_global) { is_qml_global_ = is_qml_global; }
+ private:
+ Scope* scope_;
+ Handle<String> name_;
+@@ -159,6 +161,9 @@ class Variable: public ZoneObject {
+ // Usage info.
+ bool is_accessed_from_inner_scope_; // set by variable resolver
+ bool is_used_;
++
++ // QML info
++ bool is_qml_global_;
+ };
+
+
+diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
+index c365385..d923494 100644
+--- a/src/x64/code-stubs-x64.cc
++++ b/src/x64/code-stubs-x64.cc
+@@ -140,6 +140,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
+ __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
+
++ // Copy the qml global object from the surrounding context.
++ __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++ __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), rbx);
++
+ // Initialize the rest of the slots to undefined.
+ __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
+diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
+index 97168cd..c45cdb6 100644
+--- a/src/x64/full-codegen-x64.cc
++++ b/src/x64/full-codegen-x64.cc
+@@ -141,12 +141,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment cmnt(masm_, "[ Allocate local context");
+ // Argument to NewContext is the function, which is still in rdi.
+ __ push(rdi);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -1119,10 +1120,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+
+ // All extension objects were empty and it is safe to use a global
+ // load IC call.
+- __ movq(rax, GlobalObjectOperand());
++ __ movq(rax, slot->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ Move(rcx, slot->var()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global())
+ ? RelocInfo::CODE_TARGET
+ : RelocInfo::CODE_TARGET_CONTEXT;
+ EmitCallIC(ic, mode);
+@@ -1227,9 +1228,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
+ // Use inline caching. Variable name is passed in rcx and the global
+ // object on the stack.
+ __ Move(rcx, var->name());
+- __ movq(rax, GlobalObjectOperand());
++ __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(rax);
+
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+@@ -1806,11 +1807,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+ // assignment. Right-hand-side value is passed in rax, variable name in
+ // rcx, and the global object on the stack.
+ __ Move(rcx, var->name());
+- __ movq(rdx, GlobalObjectOperand());
++ __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (op == Token::INIT_CONST) {
+ // Like var declarations, const declarations are hoisted to function
+@@ -2085,9 +2086,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
+ // Push the strict mode flag.
+ __ Push(Smi::FromInt(strict_mode_flag()));
+
++ // Push the qml mode flag
++ __ Push(Smi::FromInt(is_qml_mode()));
++
+ __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
+ ? Runtime::kResolvePossiblyDirectEvalNoLookup
+- : Runtime::kResolvePossiblyDirectEval, 4);
++ : Runtime::kResolvePossiblyDirectEval, 5);
+ }
+
+
+@@ -2160,8 +2164,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Call to a global variable.
+ // Push global object as receiver for the call IC lookup.
+- __ push(GlobalObjectOperand());
+- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
++ __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
++ EmitCallWithIC(expr, var->name(), var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (var != NULL && var->AsSlot() != NULL &&
+ var->AsSlot()->type() == Slot::LOOKUP) {
+ // Call to a lookup slot (dynamically introduced variable).
+diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
+index 202e7a2..45acbdf 100644
+--- a/src/x64/lithium-codegen-x64.cc
++++ b/src/x64/lithium-codegen-x64.cc
+@@ -174,12 +174,13 @@ bool LCodeGen::GeneratePrologue() {
+
+ // Possibly allocate a local context.
+ int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+- if (heap_slots > 0) {
++ if (heap_slots > 0 ||
++ (scope()->is_qml_mode() && scope()->is_global_scope())) {
+ Comment(";;; Allocate local context");
+ // Argument to NewContext is the function, which is still in rdi.
+ __ push(rdi);
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+- FastNewContextStub stub(heap_slots);
++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kNewContext, 1);
+@@ -2540,7 +2541,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) {
+
+ void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
+ Register result = ToRegister(instr->result());
+- __ movq(result, GlobalObjectOperand());
++ __ movq(result, instr->qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ }
+
+
+diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
+index 07ca3a5..00feeac 100644
+--- a/src/x64/lithium-x64.cc
++++ b/src/x64/lithium-x64.cc
+@@ -1194,7 +1194,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
+
+
+ LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
+- return DefineAsRegister(new LGlobalObject);
++ return DefineAsRegister(new LGlobalObject(instr->qml_global()));
+ }
+
+
+diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
+index 15bb894..16f754c 100644
+--- a/src/x64/lithium-x64.h
++++ b/src/x64/lithium-x64.h
+@@ -1365,7 +1365,13 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> {
+
+ class LGlobalObject: public LTemplateInstruction<1, 0, 0> {
+ public:
++ explicit LGlobalObject(bool qml_global) : qml_global_(qml_global) {}
++
+ DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object")
++
++ bool qml_global() { return qml_global_; }
++ private:
++ bool qml_global_;
+ };
+
+
+diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
+index 4c17720..aa284ed 100644
+--- a/src/x64/macro-assembler-x64.h
++++ b/src/x64/macro-assembler-x64.h
+@@ -1233,6 +1233,11 @@ static inline Operand GlobalObjectOperand() {
+ }
+
+
++static inline Operand QmlGlobalObjectOperand() {
++ return ContextOperand(rsi, Context::QML_GLOBAL_INDEX);
++}
++
++
+ // Provides access to exit frame stack space (not GCed).
+ static inline Operand StackSpaceOperand(int index) {
+ #ifdef _WIN64
+--
+1.7.2.3
+
diff --git a/src/v8/0006-Allow-access-to-the-calling-script-data.patch b/src/v8/0006-Allow-access-to-the-calling-script-data.patch
new file mode 100644
index 0000000000..d4acdf7a42
--- /dev/null
+++ b/src/v8/0006-Allow-access-to-the-calling-script-data.patch
@@ -0,0 +1,48 @@
+From f890f0d1a1e5bd62711815489c87755a4f382436 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Wed, 25 May 2011 10:36:13 +1000
+Subject: [PATCH 06/13] Allow access to the calling script data
+
+---
+ include/v8.h | 1 +
+ src/api.cc | 12 ++++++++++++
+ 2 files changed, 13 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index a858eae..9aba4a8 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -3336,6 +3336,7 @@ class V8EXPORT Context {
+ */
+ static Local<Context> GetCalling();
+ static Local<Object> GetCallingQmlGlobal();
++ static Local<Value> GetCallingScriptData();
+
+ /**
+ * Sets the security token for the context. To access an object in
+diff --git a/src/api.cc b/src/api.cc
+index 39767f4..ff74efb 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3976,6 +3976,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
+ }
+ }
+
++v8::Local<v8::Value> Context::GetCallingScriptData()
++{
++ i::Isolate* isolate = i::Isolate::Current();
++ if (IsDeadCheck(isolate, "v8::Context::GetCallingScriptData()")) {
++ return Local<Object>();
++ }
++
++ i::JavaScriptFrameIterator it;
++ if (it.done()) return Local<Object>();
++ i::Handle<i::Script> script(i::Script::cast(i::JSFunction::cast(it.frame()->function())->shared()->script()));
++ return Utils::ToLocal(i::Handle<i::Object>(script->data()));
++}
+
+ v8::Local<v8::Object> Context::Global() {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+--
+1.7.2.3
+
diff --git a/src/v8/0007-Fix-warnings.patch b/src/v8/0007-Fix-warnings.patch
new file mode 100644
index 0000000000..26141c8ae8
--- /dev/null
+++ b/src/v8/0007-Fix-warnings.patch
@@ -0,0 +1,46 @@
+From dac5d9db84cf20564621c679937ca7b9c6a8e880 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Fri, 27 May 2011 13:04:15 +1000
+Subject: [PATCH 07/13] Fix warnings
+
+---
+ include/v8.h | 16 ++++++++--------
+ 1 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 9aba4a8..8891dab 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -2415,7 +2415,7 @@ class V8EXPORT Extension { // NOLINT
+ const char** deps = 0);
+ virtual ~Extension() { }
+ virtual v8::Handle<v8::FunctionTemplate>
+- GetNativeFunction(v8::Handle<v8::String> name) {
++ GetNativeFunction(v8::Handle<v8::String>) {
+ return v8::Handle<v8::FunctionTemplate>();
+ }
+
+@@ -3721,13 +3721,13 @@ class Internals {
+ return *reinterpret_cast<T*>(addr);
+ }
+
+- static inline bool CanCastToHeapObject(void* o) { return false; }
+- static inline bool CanCastToHeapObject(Context* o) { return true; }
+- static inline bool CanCastToHeapObject(String* o) { return true; }
+- static inline bool CanCastToHeapObject(Object* o) { return true; }
+- static inline bool CanCastToHeapObject(Message* o) { return true; }
+- static inline bool CanCastToHeapObject(StackTrace* o) { return true; }
+- static inline bool CanCastToHeapObject(StackFrame* o) { return true; }
++ static inline bool CanCastToHeapObject(void*) { return false; }
++ static inline bool CanCastToHeapObject(Context*) { return true; }
++ static inline bool CanCastToHeapObject(String*) { return true; }
++ static inline bool CanCastToHeapObject(Object*) { return true; }
++ static inline bool CanCastToHeapObject(Message*) { return true; }
++ static inline bool CanCastToHeapObject(StackTrace*) { return true; }
++ static inline bool CanCastToHeapObject(StackFrame*) { return true; }
+ };
+
+ } // namespace internal
+--
+1.7.2.3
+
diff --git a/src/v8/0008-Add-custom-object-compare-callback.patch b/src/v8/0008-Add-custom-object-compare-callback.patch
new file mode 100644
index 0000000000..d7ef5c434d
--- /dev/null
+++ b/src/v8/0008-Add-custom-object-compare-callback.patch
@@ -0,0 +1,489 @@
+From bec11b8b7f89d135e7d9a823ac4fe98c70d017cf Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 27 Jun 2011 14:57:28 +1000
+Subject: [PATCH 08/13] Add custom object compare callback
+
+A global custom object comparison callback can be set with:
+ V8::SetUserObjectComparisonCallbackFunction()
+When two JSObjects are compared (== or !=), if either one has
+the MarkAsUseUserObjectComparison() bit set, the custom comparison
+callback is invoked to do the actual comparison.
+
+This is useful when you have "value" objects that you want to
+compare as equal, even though they are actually different JS object
+instances.
+---
+ include/v8.h | 13 +++++++++++++
+ src/api.cc | 19 +++++++++++++++++++
+ src/arm/code-stubs-arm.cc | 42 ++++++++++++++++++++++++++++++++++++++++--
+ src/factory.cc | 8 ++++++++
+ src/ia32/code-stubs-ia32.cc | 40 ++++++++++++++++++++++++++++++++++++++++
+ src/isolate.h | 8 ++++++++
+ src/objects-inl.h | 15 +++++++++++++++
+ src/objects.h | 10 +++++++++-
+ src/runtime.cc | 23 +++++++++++++++++++++++
+ src/runtime.h | 1 +
+ src/top.cc | 5 +++++
+ src/x64/code-stubs-x64.cc | 37 +++++++++++++++++++++++++++++++++++++
+ 12 files changed, 218 insertions(+), 3 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 8891dab..d5d6972 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -2365,6 +2365,12 @@ class V8EXPORT ObjectTemplate : public Template {
+ bool HasExternalResource();
+ void SetHasExternalResource(bool value);
+
++ /**
++ * Mark object instances of the template as using the user object
++ * comparison callback.
++ */
++ void MarkAsUseUserObjectComparison();
++
+ private:
+ ObjectTemplate();
+ static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
+@@ -2565,6 +2571,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
+ AccessType type,
+ Local<Value> data);
+
++// --- U s e r O b j e c t C o m p a r i s o n C a l l b a c k ---
++typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
++ Local<Object> rhs);
++
+ // --- G a r b a g e C o l l e c t i o n C a l l b a c k s
+
+ /**
+@@ -2815,6 +2825,9 @@ class V8EXPORT V8 {
+ /** Callback function for reporting failed access checks.*/
+ static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
+
++ /** Callback for user object comparisons */
++ static void SetUserObjectComparisonCallbackFunction(UserObjectComparisonCallback);
++
+ /**
+ * Enables the host application to receive a notification before a
+ * garbage collection. Allocations are not allowed in the
+diff --git a/src/api.cc b/src/api.cc
+index ff74efb..2436031 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -1321,6 +1321,16 @@ void ObjectTemplate::SetHasExternalResource(bool value)
+ }
+ }
+
++void ObjectTemplate::MarkAsUseUserObjectComparison()
++{
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUseUserObjectComparison()")) {
++ return;
++ }
++ ENTER_V8(isolate);
++ EnsureConstructor(this);
++ Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1));
++}
+
+ // --- S c r i p t D a t a ---
+
+@@ -4632,6 +4642,15 @@ void V8::SetFailedAccessCheckCallbackFunction(
+ isolate->SetFailedAccessCheckCallback(callback);
+ }
+
++void V8::SetUserObjectComparisonCallbackFunction(
++ UserObjectComparisonCallback callback) {
++ i::Isolate* isolate = i::Isolate::Current();
++ if (IsDeadCheck(isolate, "v8::V8::SetUserObjectComparisonCallbackFunction()")) {
++ return;
++ }
++ isolate->SetUserObjectComparisonCallback(callback);
++}
++
+ void V8::AddObjectGroup(Persistent<Value>* objects,
+ size_t length,
+ RetainedObjectInfo* info) {
+diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
+index a2626bf..749c9be 100644
+--- a/src/arm/code-stubs-arm.cc
++++ b/src/arm/code-stubs-arm.cc
+@@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) {
+ // NOTICE! This code is only reached after a smi-fast-case check, so
+ // it is certain that at least one operand isn't a smi.
+
++ {
++ Label not_user_equal, user_equal;
++ __ and_(r2, r1, Operand(r0));
++ __ tst(r2, Operand(kSmiTagMask));
++ __ b(eq, &not_user_equal);
++
++ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
++ __ b(ne, &not_user_equal);
++
++ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
++ __ b(ne, &not_user_equal);
++
++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ b(eq, &user_equal);
++
++ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset));
++ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
++ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
++ __ b(ne, &not_user_equal);
++
++ __ bind(&user_equal);
++
++ __ Push(r0, r1);
++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++
++ __ bind(&not_user_equal);
++ }
++
+ // Handle the case where the objects are identical. Either returns the answer
+ // or goes to slow. Only falls through if the objects were not identical.
+ EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
+@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+ __ tst(r2, Operand(kSmiTagMask));
+ __ b(eq, &miss);
+
+- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
++ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
+ __ b(ne, &miss);
+- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ b(eq, &miss);
++ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
+ __ b(ne, &miss);
++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++ __ b(eq, &miss);
+
+ ASSERT(GetCondition() == eq);
+ __ sub(r0, r0, Operand(r1));
+diff --git a/src/factory.cc b/src/factory.cc
+index d530a75..6f8c7de 100644
+--- a/src/factory.cc
++++ b/src/factory.cc
+@@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
+
+ int internal_field_count = 0;
+ bool has_external_resource = false;
++ bool use_user_object_comparison = false;
+
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance_template =
+@@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
+ Smi::cast(instance_template->internal_field_count())->value();
+ has_external_resource =
+ !instance_template->has_external_resource()->IsUndefined();
++ use_user_object_comparison =
++ !instance_template->use_user_object_comparison()->IsUndefined();
+ }
+
+ int instance_size = kPointerSize * internal_field_count;
+@@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
+ map->set_has_external_resource(true);
+ }
+
++ // Mark as using user object comparison if needed
++ if (use_user_object_comparison) {
++ map->set_use_user_object_comparison(true);
++ }
++
+ // Mark as undetectable if needed.
+ if (obj->undetectable()) {
+ map->set_is_undetectable();
+diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
+index afa599e..0964ab9 100644
+--- a/src/ia32/code-stubs-ia32.cc
++++ b/src/ia32/code-stubs-ia32.cc
+@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
+ __ Assert(not_zero, "Unexpected smi operands.");
+ }
+
++ {
++ NearLabel not_user_equal, user_equal;
++ __ test(eax, Immediate(kSmiTagMask));
++ __ j(zero, &not_user_equal);
++ __ test(edx, Immediate(kSmiTagMask));
++ __ j(zero, &not_user_equal);
++
++ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
++ __ j(not_equal, &not_user_equal);
++
++ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
++ __ j(not_equal, &not_user_equal);
++
++ __ test_b(FieldOperand(ebx, Map::kBitField3Offset),
++ 1 << Map::kUseUserObjectComparison);
++ __ j(not_zero, &user_equal);
++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++ 1 << Map::kUseUserObjectComparison);
++ __ j(not_zero, &user_equal);
++
++ __ jmp(&not_user_equal);
++
++ __ bind(&user_equal);
++
++ __ pop(ebx); // Return address.
++ __ push(eax);
++ __ push(edx);
++ __ push(ebx);
++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++
++ __ bind(&not_user_equal);
++ }
++
++
+ // NOTICE! This code is only reached after a smi-fast-case check, so
+ // it is certain that at least one operand isn't a smi.
+
+@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+
+ __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &miss, not_taken);
++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++ 1 << Map::kUseUserObjectComparison);
++ __ j(not_zero, &miss);
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &miss, not_taken);
++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++ 1 << Map::kUseUserObjectComparison);
++ __ j(not_zero, &miss);
+
+ ASSERT(GetCondition() == equal);
+ __ sub(eax, Operand(edx));
+diff --git a/src/isolate.h b/src/isolate.h
+index 35ffcb4..8130397 100644
+--- a/src/isolate.h
++++ b/src/isolate.h
+@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED {
+ // Call back function to report unsafe JS accesses.
+ v8::FailedAccessCheckCallback failed_access_check_callback_;
+
++ // Call back function for user object comparisons
++ v8::UserObjectComparisonCallback user_object_comparison_callback_;
++
+ private:
+ void InitializeInternal();
+
+@@ -699,6 +702,11 @@ class Isolate {
+ void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
+ void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
+
++ void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback);
++ inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() {
++ return thread_local_top()->user_object_comparison_callback_;
++ }
++
+ // Exception throwing support. The caller should use the result
+ // of Throw() as its return value.
+ Failure* Throw(Object* exception, MessageLocation* location = NULL);
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 1c7f83e..1765441 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -2552,6 +2552,19 @@ bool Map::has_external_resource()
+ }
+
+
++void Map::set_use_user_object_comparison(bool value) {
++ if (value) {
++ set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison));
++ } else {
++ set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison));
++ }
++}
++
++bool Map::use_user_object_comparison() {
++ return ((1 << kUseUserObjectComparison) & bit_field3()) != 0;
++}
++
++
+ void Map::set_named_interceptor_is_fallback(bool value)
+ {
+ if (value) {
+@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
+ kInternalFieldCountOffset)
+ ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
+ kHasExternalResourceOffset)
++ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
++ kUseUserObjectComparisonOffset)
+
+ ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
+ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
+diff --git a/src/objects.h b/src/objects.h
+index edbc47a..e75e9f1 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -3724,6 +3724,11 @@ class Map: public HeapObject {
+ inline void set_has_external_resource(bool value);
+ inline bool has_external_resource();
+
++
++ // Tells whether the user object comparison callback should be used for
++ // comparisons involving this object
++ inline void set_use_user_object_comparison(bool value);
++ inline bool use_user_object_comparison();
+
+ // Whether the named interceptor is a fallback interceptor or not
+ inline void set_named_interceptor_is_fallback(bool value);
+@@ -3922,6 +3927,7 @@ class Map: public HeapObject {
+ // Bit positions for bit field 3
+ static const int kNamedInterceptorIsFallback = 0;
+ static const int kHasExternalResource = 1;
++ static const int kUseUserObjectComparison = 2;
+
+ // Layout of the default cache. It holds alternating name and code objects.
+ static const int kCodeCacheEntrySize = 2;
+@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo {
+ DECL_ACCESSORS(constructor, Object)
+ DECL_ACCESSORS(internal_field_count, Object)
+ DECL_ACCESSORS(has_external_resource, Object)
++ DECL_ACCESSORS(use_user_object_comparison, Object)
+
+ static inline ObjectTemplateInfo* cast(Object* obj);
+
+@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo {
+ static const int kInternalFieldCountOffset =
+ kConstructorOffset + kPointerSize;
+ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
+- static const int kSize = kHasExternalResourceOffset + kPointerSize;
++ static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize;
++ static const int kSize = kUseUserObjectComparisonOffset + kPointerSize;
+ };
+
+
+diff --git a/src/runtime.cc b/src/runtime.cc
+index 827d954..d552ddb 100644
+--- a/src/runtime.cc
++++ b/src/runtime.cc
+@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
+ }
+
+
++RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
++ NoHandleAllocation ha;
++ ASSERT(args.length() == 2);
++
++ CONVERT_CHECKED(JSObject, lhs, args[1]);
++ CONVERT_CHECKED(JSObject, rhs, args[0]);
++
++ bool result;
++
++ v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
++ if (callback) {
++ HandleScope scope(isolate);
++ Handle<JSObject> lhs_handle(lhs);
++ Handle<JSObject> rhs_handle(rhs);
++ result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
++ } else {
++ result = (lhs == rhs);
++ }
++
++ return Smi::FromInt(result?0:1);
++}
++
++
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 3);
+diff --git a/src/runtime.h b/src/runtime.h
+index 5e97173..0d754f9 100644
+--- a/src/runtime.h
++++ b/src/runtime.h
+@@ -146,6 +146,7 @@ namespace internal {
+ /* Comparisons */ \
+ F(NumberEquals, 2, 1) \
+ F(StringEquals, 2, 1) \
++ F(UserObjectEquals, 2, 1) \
+ \
+ F(NumberCompare, 3, 1) \
+ F(SmiLexicographicCompare, 2, 1) \
+diff --git a/src/top.cc b/src/top.cc
+index e078ee9..c345383 100644
+--- a/src/top.cc
++++ b/src/top.cc
+@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() {
+ thread_id_ = ThreadId::Invalid();
+ external_caught_exception_ = false;
+ failed_access_check_callback_ = NULL;
++ user_object_comparison_callback_ = NULL;
+ save_context_ = NULL;
+ catcher_ = NULL;
+ }
+@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback(
+ thread_local_top()->failed_access_check_callback_ = callback;
+ }
+
++void Isolate::SetUserObjectComparisonCallback(
++ v8::UserObjectComparisonCallback callback) {
++ thread_local_top()->user_object_comparison_callback_ = callback;
++}
+
+ void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
+ if (!thread_local_top()->failed_access_check_callback_) return;
+diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
+index d923494..10b9b56 100644
+--- a/src/x64/code-stubs-x64.cc
++++ b/src/x64/code-stubs-x64.cc
+@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
+ __ bind(&ok);
+ }
+
++ {
++ NearLabel not_user_equal, user_equal;
++ __ JumpIfSmi(rax, &not_user_equal);
++ __ JumpIfSmi(rdx, &not_user_equal);
++
++ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
++ __ j(not_equal, &not_user_equal);
++
++ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
++ __ j(not_equal, &not_user_equal);
++
++ __ testb(FieldOperand(rbx, Map::kBitField3Offset),
++ Immediate(1 << Map::kUseUserObjectComparison));
++ __ j(not_zero, &user_equal);
++ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++ Immediate(1 << Map::kUseUserObjectComparison));
++ __ j(not_zero, &user_equal);
++
++ __ jmp(&not_user_equal);
++
++ __ bind(&user_equal);
++
++ __ pop(rbx); // Return address.
++ __ push(rax);
++ __ push(rdx);
++ __ push(rbx);
++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++
++ __ bind(&not_user_equal);
++ }
++
+ // The compare stub returns a positive, negative, or zero 64-bit integer
+ // value in rax, corresponding to result of comparing the two inputs.
+ // NOTICE! This code is only reached after a smi-fast-case check, so
+@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+
+ __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &miss, not_taken);
++ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++ Immediate(1 << Map::kUseUserObjectComparison));
++ __ j(not_zero, &miss);
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &miss, not_taken);
++ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++ Immediate(1 << Map::kUseUserObjectComparison));
++ __ j(not_zero, &miss);
+
+ ASSERT(GetCondition() == equal);
+ __ subq(rax, rdx);
+--
+1.7.2.3
+
diff --git a/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch
new file mode 100644
index 0000000000..d197ac9e48
--- /dev/null
+++ b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch
@@ -0,0 +1,286 @@
+From 4183b973ed3bd603784c798dfa63ba48f6b68003 Mon Sep 17 00:00:00 2001
+From: ager@chromium.org <ager@chromium.org>
+Date: Wed, 4 May 2011 13:03:08 +0000
+Subject: [PATCH 09/13] Add CallAsFunction method to the Object class in the API
+
+Patch by Peter Varga.
+
+BUG=v8:1336
+TEST=cctest/test-api/CallAsFunction
+
+Review URL: http://codereview.chromium.org/6883045
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
+---
+ include/v8.h | 8 +++
+ src/api.cc | 31 +++++++++++
+ src/execution.cc | 24 ++++++++
+ src/execution.h | 2 +
+ test/cctest/test-api.cc | 135 ++++++++++++++++++++++++++++++++++-------------
+ 5 files changed, 163 insertions(+), 37 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index d5d6972..8a8e1cd 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1757,6 +1757,14 @@ class Object : public Value {
+ V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType();
+ V8EXPORT int GetIndexedPropertiesExternalArrayDataLength();
+
++ /**
++ * Call an Object as a function if a callback is set by the
++ * ObjectTemplate::SetCallAsFunctionHandler method.
++ */
++ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
++ int argc,
++ Handle<Value> argv[]);
++
+ V8EXPORT static Local<Object> New();
+ static inline Object* Cast(Value* obj);
+ private:
+diff --git a/src/api.cc b/src/api.cc
+index 2436031..e412e51 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3259,6 +3259,37 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() {
+ }
+
+
++Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
++ v8::Handle<v8::Value> argv[]) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
++ return Local<v8::Value>());
++ LOG_API(isolate, "Object::CallAsFunction");
++ ENTER_V8(isolate);
++ HandleScope scope;
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
++ i::Object*** args = reinterpret_cast<i::Object***>(argv);
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
++ if (obj->IsJSFunction()) {
++ fun = i::Handle<i::JSFunction>::cast(obj);
++ } else {
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> delegate =
++ i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
++ fun = i::Handle<i::JSFunction>::cast(delegate);
++ recv_obj = obj;
++ }
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
++ return scope.Close(Utils::ToLocal(returned));
++}
++
++
+ Local<v8::Object> Function::NewInstance() const {
+ return NewInstance(0, NULL);
+ }
+diff --git a/src/execution.cc b/src/execution.cc
+index 1632076..894d741 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -254,6 +254,30 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
+ }
+
+
++Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
++ bool* has_pending_exception) {
++ ASSERT(!object->IsJSFunction());
++ Isolate* isolate = Isolate::Current();
++
++ // Objects created through the API can have an instance-call handler
++ // that should be used when calling the object as a function.
++ if (object->IsHeapObject() &&
++ HeapObject::cast(*object)->map()->has_instance_call_handler()) {
++ return Handle<JSFunction>(
++ isolate->global_context()->call_as_function_delegate());
++ }
++
++ // If the Object doesn't have an instance-call handler we should
++ // throw a non-callable exception.
++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
++ "called_non_callable", i::HandleVector<i::Object>(&object, 1));
++ isolate->Throw(*error_obj);
++ *has_pending_exception = true;
++
++ return isolate->factory()->undefined_value();
++}
++
++
+ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
+ ASSERT(!object->IsJSFunction());
+ Isolate* isolate = Isolate::Current();
+diff --git a/src/execution.h b/src/execution.h
+index a476eb4..0a0be51 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -144,6 +144,8 @@ class Execution : public AllStatic {
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as functions.
+ static Handle<Object> GetFunctionDelegate(Handle<Object> object);
++ static Handle<Object> TryGetFunctionDelegate(Handle<Object> object,
++ bool* has_pending_exception);
+
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as constructors.
+diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
+index d7621d1..693d51e 100644
+--- a/test/cctest/test-api.cc
++++ b/test/cctest/test-api.cc
+@@ -6962,50 +6962,111 @@ THREADED_TEST(CallAsFunction) {
+ v8::HandleScope scope;
+ LocalContext context;
+
+- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+- Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+- instance_template->SetCallAsFunctionHandler(call_as_function);
+- Local<v8::Object> instance = t->GetFunction()->NewInstance();
+- context->Global()->Set(v8_str("obj"), instance);
+- v8::TryCatch try_catch;
+- Local<Value> value;
+- CHECK(!try_catch.HasCaught());
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ instance_template->SetCallAsFunctionHandler(call_as_function);
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
+
+- value = CompileRun("obj(42)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(42, value->Int32Value());
++ value = CompileRun("obj(42)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(42, value->Int32Value());
+
+- value = CompileRun("(function(o){return o(49)})(obj)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(49, value->Int32Value());
++ value = CompileRun("(function(o){return o(49)})(obj)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(49, value->Int32Value());
+
+- // test special case of call as function
+- value = CompileRun("[obj]['0'](45)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(45, value->Int32Value());
++ // test special case of call as function
++ value = CompileRun("[obj]['0'](45)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(45, value->Int32Value());
+
+- value = CompileRun("obj.call = Function.prototype.call;"
+- "obj.call(null, 87)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(87, value->Int32Value());
++ value = CompileRun("obj.call = Function.prototype.call;"
++ "obj.call(null, 87)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(87, value->Int32Value());
+
+- // Regression tests for bug #1116356: Calling call through call/apply
+- // must work for non-function receivers.
+- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
+- value = CompileRun(apply_99);
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(99, value->Int32Value());
++ // Regression tests for bug #1116356: Calling call through call/apply
++ // must work for non-function receivers.
++ const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
++ value = CompileRun(apply_99);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(99, value->Int32Value());
+
+- const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
+- value = CompileRun(call_17);
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(17, value->Int32Value());
++ const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
++ value = CompileRun(call_17);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(17, value->Int32Value());
+
+- // Check that the call-as-function handler can be called through
+- // new.
+- value = CompileRun("new obj(43)");
+- CHECK(!try_catch.HasCaught());
+- CHECK_EQ(-43, value->Int32Value());
++ // Check that the call-as-function handler can be called through
++ // new.
++ value = CompileRun("new obj(43)");
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(-43, value->Int32Value());
++
++ // Check that the call-as-function handler can be called through
++ // the API.
++ v8::Handle<Value> args[] = { v8_num(28) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(28, value->Int32Value());
++ }
++
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj2"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Call an object without call-as-function handler through the JS
++ value = CompileRun("obj2(28)");
++ CHECK(value.IsEmpty());
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ(*exception_value1,
++ "TypeError: Property 'obj2' of object "
++ "#<Object> is not a function");
++ try_catch.Reset();
++
++ // Call an object without call-as-function handler through the API
++ value = CompileRun("obj2(28)");
++ v8::Handle<Value> args[] = { v8_num(28) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(value.IsEmpty());
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function");
++ try_catch.Reset();
++ }
++
++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
++ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
++ instance_template->SetCallAsFunctionHandler(ThrowValue);
++ Local<v8::Object> instance = t->GetFunction()->NewInstance();
++ context->Global()->Set(v8_str("obj3"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Catch the exception which is thrown by call-as-function handler
++ value = CompileRun("obj3(22)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ(*exception_value1, "22");
++ try_catch.Reset();
++
++ v8::Handle<Value> args[] = { v8_num(23) };
++ value = instance->CallAsFunction(instance, 1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ(*exception_value2, "23");
++ try_catch.Reset();
++ }
+ }
+
+
+--
+1.7.2.3
+
diff --git a/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch
new file mode 100644
index 0000000000..cb4dd186d6
--- /dev/null
+++ b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch
@@ -0,0 +1,397 @@
+From 3d6d4249878f7960eac4c9c94e0f2529f9a58c4a Mon Sep 17 00:00:00 2001
+From: ager@chromium.org <ager@chromium.org>
+Date: Fri, 6 May 2011 11:07:52 +0000
+Subject: [PATCH 10/13] Implement CallAsConstructor method for Object in the API
+
+Patch by Peter Varga.
+
+BUG=v8:1348
+TEST=cctest/test-api/ConstructorForObject
+
+Review URL: http://codereview.chromium.org/6902108
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7803 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
+---
+ include/v8.h | 8 ++
+ src/api.cc | 41 +++++++++-
+ src/execution.cc | 28 +++++++
+ src/execution.h | 2 +
+ test/cctest/test-api.cc | 205 +++++++++++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 276 insertions(+), 8 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 8a8e1cd..84462b5 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1765,6 +1765,14 @@ class Object : public Value {
+ int argc,
+ Handle<Value> argv[]);
+
++ /**
++ * Call an Object as a consturctor if a callback is set by the
++ * ObjectTemplate::SetCallAsFunctionHandler method.
++ * Note: This method behaves like the Function::NewInstance method.
++ */
++ V8EXPORT Local<Value> CallAsConstructor(int argc,
++ Handle<Value> argv[]);
++
+ V8EXPORT static Local<Object> New();
+ static inline Object* Cast(Value* obj);
+ private:
+diff --git a/src/api.cc b/src/api.cc
+index e412e51..1a585d6 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3266,7 +3266,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+ return Local<v8::Value>());
+ LOG_API(isolate, "Object::CallAsFunction");
+ ENTER_V8(isolate);
+- HandleScope scope;
++ i::HandleScope scope(isolate);
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+@@ -3286,7 +3286,44 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+ i::Handle<i::Object> returned =
+ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+- return scope.Close(Utils::ToLocal(returned));
++ return Utils::ToLocal(scope.CloseAndEscape(returned));
++}
++
++
++Local<v8::Value> Object::CallAsConstructor(int argc,
++ v8::Handle<v8::Value> argv[]) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()",
++ return Local<v8::Object>());
++ LOG_API(isolate, "Object::CallAsConstructor");
++ ENTER_V8(isolate);
++ i::HandleScope scope(isolate);
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
++ i::Object*** args = reinterpret_cast<i::Object***>(argv);
++ if (obj->IsJSFunction()) {
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj);
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::New(fun, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ return Utils::ToLocal(scope.CloseAndEscape(
++ i::Handle<i::JSObject>::cast(returned)));
++ }
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> delegate =
++ i::Execution::TryGetConstructorDelegate(obj, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ if (!delegate->IsUndefined()) {
++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate);
++ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> returned =
++ i::Execution::Call(fun, obj, argc, args, &has_pending_exception);
++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
++ ASSERT(!delegate->IsUndefined());
++ return Utils::ToLocal(scope.CloseAndEscape(returned));
++ }
++ return Local<v8::Object>();
+ }
+
+
+diff --git a/src/execution.cc b/src/execution.cc
+index 894d741..afb352c 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -297,6 +297,34 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
+ }
+
+
++Handle<Object> Execution::TryGetConstructorDelegate(
++ Handle<Object> object,
++ bool* has_pending_exception) {
++ ASSERT(!object->IsJSFunction());
++ Isolate* isolate = Isolate::Current();
++
++ // If you return a function from here, it will be called when an
++ // attempt is made to call the given object as a constructor.
++
++ // Objects created through the API can have an instance-call handler
++ // that should be used when calling the object as a function.
++ if (object->IsHeapObject() &&
++ HeapObject::cast(*object)->map()->has_instance_call_handler()) {
++ return Handle<JSFunction>(
++ isolate->global_context()->call_as_constructor_delegate());
++ }
++
++ // If the Object doesn't have an instance-call handler we should
++ // throw a non-callable exception.
++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
++ "called_non_callable", i::HandleVector<i::Object>(&object, 1));
++ isolate->Throw(*error_obj);
++ *has_pending_exception = true;
++
++ return isolate->factory()->undefined_value();
++}
++
++
+ bool StackGuard::IsStackOverflow() {
+ ExecutionAccess access(isolate_);
+ return (thread_local_.jslimit_ != kInterruptLimit &&
+diff --git a/src/execution.h b/src/execution.h
+index 0a0be51..ec2a195 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -150,6 +150,8 @@ class Execution : public AllStatic {
+ // Get a function delegate (or undefined) for the given non-function
+ // object. Used for support calling objects as constructors.
+ static Handle<Object> GetConstructorDelegate(Handle<Object> object);
++ static Handle<Object> TryGetConstructorDelegate(Handle<Object> object,
++ bool* has_pending_exception);
+ };
+
+
+diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
+index 693d51e..1334f63 100644
+--- a/test/cctest/test-api.cc
++++ b/test/cctest/test-api.cc
+@@ -6746,6 +6746,200 @@ THREADED_TEST(Constructor) {
+ CHECK(value->BooleanValue());
+ }
+
++
++static Handle<Value> ConstructorCallback(const Arguments& args) {
++ ApiTestFuzzer::Fuzz();
++ Local<Object> This;
++
++ if (args.IsConstructCall()) {
++ Local<Object> Holder = args.Holder();
++ This = Object::New();
++ Local<Value> proto = Holder->GetPrototype();
++ if (proto->IsObject()) {
++ This->SetPrototype(proto);
++ }
++ } else {
++ This = args.This();
++ }
++
++ This->Set(v8_str("a"), args[0]);
++ return This;
++}
++
++
++static Handle<Value> FakeConstructorCallback(const Arguments& args) {
++ ApiTestFuzzer::Fuzz();
++ return args[0];
++}
++
++
++THREADED_TEST(ConstructorForObject) {
++ v8::HandleScope handle_scope;
++ LocalContext context;
++
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(ConstructorCallback);
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ // Call the Object's constructor with a 32-bit signed integer.
++ value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsInt32());
++ CHECK_EQ(28, value->Int32Value());
++
++ Local<Value> args1[] = { v8_num(28) };
++ Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
++ CHECK(value_obj1->IsObject());
++ Local<Object> object1 = Local<Object>::Cast(value_obj1);
++ value = object1->Get(v8_str("a"));
++ CHECK(value->IsInt32());
++ CHECK(!try_catch.HasCaught());
++ CHECK_EQ(28, value->Int32Value());
++
++ // Call the Object's constructor with a String.
++ value = CompileRun(
++ "(function() { var o = new obj('tipli'); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsString());
++ String::AsciiValue string_value1(value->ToString());
++ CHECK_EQ("tipli", *string_value1);
++
++ Local<Value> args2[] = { v8_str("tipli") };
++ Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
++ CHECK(value_obj2->IsObject());
++ Local<Object> object2 = Local<Object>::Cast(value_obj2);
++ value = object2->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsString());
++ String::AsciiValue string_value2(value->ToString());
++ CHECK_EQ("tipli", *string_value2);
++
++ // Call the Object's constructor with a Boolean.
++ value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsBoolean());
++ CHECK_EQ(true, value->BooleanValue());
++
++ Handle<Value> args3[] = { v8::Boolean::New(true) };
++ Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
++ CHECK(value_obj3->IsObject());
++ Local<Object> object3 = Local<Object>::Cast(value_obj3);
++ value = object3->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsBoolean());
++ CHECK_EQ(true, value->BooleanValue());
++
++ // Call the Object's constructor with undefined.
++ Handle<Value> args4[] = { v8::Undefined() };
++ Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
++ CHECK(value_obj4->IsObject());
++ Local<Object> object4 = Local<Object>::Cast(value_obj4);
++ value = object4->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsUndefined());
++
++ // Call the Object's constructor with null.
++ Handle<Value> args5[] = { v8::Null() };
++ Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
++ CHECK(value_obj5->IsObject());
++ Local<Object> object5 = Local<Object>::Cast(value_obj5);
++ value = object5->Get(v8_str("a"));
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsNull());
++ }
++
++ // Check exception handling when there is no constructor set for the Object.
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj2"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ value = CompileRun("new obj2(28)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ("TypeError: object is not a function", *exception_value1);
++ try_catch.Reset();
++
++ Local<Value> args[] = { v8_num(29) };
++ value = instance->CallAsConstructor(1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
++ try_catch.Reset();
++ }
++
++ // Check the case when constructor throws exception.
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(ThrowValue);
++ Local<Object> instance = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj3"), instance);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ value = CompileRun("new obj3(22)");
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value1(try_catch.Exception());
++ CHECK_EQ("22", *exception_value1);
++ try_catch.Reset();
++
++ Local<Value> args[] = { v8_num(23) };
++ value = instance->CallAsConstructor(1, args);
++ CHECK(try_catch.HasCaught());
++ String::AsciiValue exception_value2(try_catch.Exception());
++ CHECK_EQ("23", *exception_value2);
++ try_catch.Reset();
++ }
++
++ // Check whether constructor returns with an object or non-object.
++ { Local<FunctionTemplate> function_template =
++ FunctionTemplate::New(FakeConstructorCallback);
++ Local<Function> function = function_template->GetFunction();
++ Local<Object> instance1 = function;
++ context->Global()->Set(v8_str("obj4"), instance1);
++ v8::TryCatch try_catch;
++ Local<Value> value;
++ CHECK(!try_catch.HasCaught());
++
++ CHECK(instance1->IsObject());
++ CHECK(instance1->IsFunction());
++
++ value = CompileRun("new obj4(28)");
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsObject());
++
++ Local<Value> args1[] = { v8_num(28) };
++ value = instance1->CallAsConstructor(1, args1);
++ CHECK(!try_catch.HasCaught());
++ CHECK(value->IsObject());
++
++ Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
++ Local<Object> instance2 = instance_template->NewInstance();
++ context->Global()->Set(v8_str("obj5"), instance2);
++ CHECK(!try_catch.HasCaught());
++
++ CHECK(instance2->IsObject());
++ CHECK(!instance2->IsFunction());
++
++ value = CompileRun("new obj5(28)");
++ CHECK(!try_catch.HasCaught());
++ CHECK(!value->IsObject());
++
++ Local<Value> args2[] = { v8_num(28) };
++ value = instance2->CallAsConstructor(1, args2);
++ CHECK(!try_catch.HasCaught());
++ CHECK(!value->IsObject());
++ }
++}
++
++
+ THREADED_TEST(FunctionDescriptorException) {
+ v8::HandleScope handle_scope;
+ LocalContext context;
+@@ -7028,9 +7222,8 @@ THREADED_TEST(CallAsFunction) {
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+- CHECK_EQ(*exception_value1,
+- "TypeError: Property 'obj2' of object "
+- "#<Object> is not a function");
++ CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
++ *exception_value1);
+ try_catch.Reset();
+
+ // Call an object without call-as-function handler through the API
+@@ -7040,7 +7233,7 @@ THREADED_TEST(CallAsFunction) {
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+- CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function");
++ CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
+ try_catch.Reset();
+ }
+
+@@ -7057,14 +7250,14 @@ THREADED_TEST(CallAsFunction) {
+ value = CompileRun("obj3(22)");
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+- CHECK_EQ(*exception_value1, "22");
++ CHECK_EQ("22", *exception_value1);
+ try_catch.Reset();
+
+ v8::Handle<Value> args[] = { v8_num(23) };
+ value = instance->CallAsFunction(instance, 1, args);
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+- CHECK_EQ(*exception_value2, "23");
++ CHECK_EQ("23", *exception_value2);
+ try_catch.Reset();
+ }
+ }
+--
+1.7.2.3
+
diff --git a/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch
new file mode 100644
index 0000000000..9c0e68352f
--- /dev/null
+++ b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch
@@ -0,0 +1,63 @@
+From f22d0312faeb93ced8747d9aae8c6d77e11b4aba Mon Sep 17 00:00:00 2001
+From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+Date: Tue, 7 Dec 2010 11:56:42 +0100
+Subject: [PATCH 11/13] QtScript/V8: Add new v8 api to check if a value is an error.
+
+New function v8::Value::IsError was created.
+
+This API is experimental and added only for the purposes of our
+research.
+---
+ include/v8.h | 5 +++++
+ src/api.cc | 6 ++++++
+ src/heap.h | 1 +
+ 3 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 84462b5..08b0ec2 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -937,6 +937,11 @@ class Value : public Data {
+ */
+ V8EXPORT bool IsRegExp() const;
+
++ /**
++ * Returns true if this value is an Error.
++ */
++ V8EXPORT bool IsError() const;
++
+ V8EXPORT Local<Boolean> ToBoolean() const;
+ V8EXPORT Local<Number> ToNumber() const;
+ V8EXPORT Local<String> ToString() const;
+diff --git a/src/api.cc b/src/api.cc
+index 1a585d6..bd435eb 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const {
+ return obj->IsJSRegExp();
+ }
+
++bool Value::IsError() const {
++ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsError()")) return false;
++ i::Handle<i::Object> obj = Utils::OpenHandle(this);
++ return obj->HasSpecificClassOf(HEAP->Error_symbol());
++}
++
+
+ Local<String> Value::ToString() const {
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+diff --git a/src/heap.h b/src/heap.h
+index 8cbf378..db90bb9 100644
+--- a/src/heap.h
++++ b/src/heap.h
+@@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_();
+ V(string_symbol, "string") \
+ V(String_symbol, "String") \
+ V(Date_symbol, "Date") \
++ V(Error_symbol, "Error") \
+ V(this_symbol, "this") \
+ V(to_string_symbol, "toString") \
+ V(char_at_symbol, "CharAt") \
+--
+1.7.2.3
+
diff --git a/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch b/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch
new file mode 100644
index 0000000000..77589c8af3
--- /dev/null
+++ b/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch
@@ -0,0 +1,116 @@
+From 472c04c9e7a64e8734c76d2cf97a7cc5b773b788 Mon Sep 17 00:00:00 2001
+From: ager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
+Date: Mon, 9 May 2011 15:24:48 +0000
+Subject: [PATCH 12/13] Add IsCallable method for Object in the API
+
+Patch by Peter Varga.
+
+BUG=none
+TEST=cctest/test-api/CallableObject
+
+Review URL: http://codereview.chromium.org/6964005
+
+git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7828 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
+---
+ include/v8.h | 7 +++++++
+ src/api.cc | 11 +++++++++++
+ test/cctest/test-api.cc | 43 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 61 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 08b0ec2..4194d4a 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1763,6 +1763,13 @@ class Object : public Value {
+ V8EXPORT int GetIndexedPropertiesExternalArrayDataLength();
+
+ /**
++ * Checks whether a callback is set by the
++ * ObjectTemplate::SetCallAsFunctionHandler method.
++ * When an Object is callable this method returns true.
++ */
++ V8EXPORT bool IsCallable();
++
++ /**
+ * Call an Object as a function if a callback is set by the
+ * ObjectTemplate::SetCallAsFunctionHandler method.
+ */
+diff --git a/src/api.cc b/src/api.cc
+index bd435eb..a5a637f 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3265,6 +3265,17 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() {
+ }
+
+
++bool v8::Object::IsCallable() {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ON_BAILOUT(isolate, "v8::Object::IsCallable()", return false);
++ ENTER_V8(isolate);
++ i::HandleScope scope(isolate);
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ if (obj->IsJSFunction()) return true;
++ return i::Execution::GetFunctionDelegate(obj)->IsJSFunction();
++}
++
++
+ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc,
+ v8::Handle<v8::Value> argv[]) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
+index 1334f63..45db5a1 100644
+--- a/test/cctest/test-api.cc
++++ b/test/cctest/test-api.cc
+@@ -7263,6 +7263,49 @@ THREADED_TEST(CallAsFunction) {
+ }
+
+
++// Check whether a non-function object is callable.
++THREADED_TEST(CallableObject) {
++ v8::HandleScope scope;
++ LocalContext context;
++
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ instance_template->SetCallAsFunctionHandler(call_as_function);
++ Local<Object> instance = instance_template->NewInstance();
++ v8::TryCatch try_catch;
++
++ CHECK(instance->IsCallable());
++ CHECK(!try_catch.HasCaught());
++ }
++
++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
++ Local<Object> instance = instance_template->NewInstance();
++ v8::TryCatch try_catch;
++
++ CHECK(!instance->IsCallable());
++ CHECK(!try_catch.HasCaught());
++ }
++
++ { Local<FunctionTemplate> function_template =
++ FunctionTemplate::New(call_as_function);
++ Local<Function> function = function_template->GetFunction();
++ Local<Object> instance = function;
++ v8::TryCatch try_catch;
++
++ CHECK(instance->IsCallable());
++ CHECK(!try_catch.HasCaught());
++ }
++
++ { Local<FunctionTemplate> function_template = FunctionTemplate::New();
++ Local<Function> function = function_template->GetFunction();
++ Local<Object> instance = function;
++ v8::TryCatch try_catch;
++
++ CHECK(instance->IsCallable());
++ CHECK(!try_catch.HasCaught());
++ }
++}
++
++
+ static int CountHandles() {
+ return v8::HandleScope::NumberOfHandles();
+ }
+--
+1.7.2.3
+
diff --git a/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch b/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch
new file mode 100644
index 0000000000..6bad561273
--- /dev/null
+++ b/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch
@@ -0,0 +1,15 @@
+From dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Thu, 25 Aug 2011 11:09:58 +1000
+Subject: [PATCH 13/13] Remove execute flag from v8-debug.h
+
+---
+ 0 files changed, 0 insertions(+), 0 deletions(-)
+ mode change 100755 => 100644 include/v8-debug.h
+
+diff --git a/include/v8-debug.h b/include/v8-debug.h
+old mode 100755
+new mode 100644
+--
+1.7.2.3
+
diff --git a/src/v8/README b/src/v8/README
new file mode 100644
index 0000000000..2dc39705aa
--- /dev/null
+++ b/src/v8/README
@@ -0,0 +1 @@
+These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2
diff --git a/src/v8/v8.pri b/src/v8/v8.pri
new file mode 100644
index 0000000000..4d55bbfd5a
--- /dev/null
+++ b/src/v8/v8.pri
@@ -0,0 +1,260 @@
+equals(QT_ARCH, x86_64)|contains(CONFIG, x86_64):CONFIG += arch_x86_64
+else:equals(QT_ARCH, "i386"):CONFIG += arch_i386
+else:equals(QT_ARCH, "arm"):CONFIG += arch_arm
+else:equals(QMAKE_HOST.arch, armv7l):CONFIG += arch_arm
+else:equals(QMAKE_HOST.arch, x86_64):CONFIG += arch_x86_64
+else:equals(QMAKE_HOST.arch, x86):CONFIG += arch_i386
+else:equals(QMAKE_HOST.arch, i386):CONFIG += arch_i386
+else:equals(QMAKE_HOST.arch, i686):CONFIG += arch_i386
+else:error("Couldn't detect supported architecture ($$QMAKE_HOST.arch/$$QT_ARCH). Currently supported architectures are: x64, x86 and arm")
+
+include($$PWD/v8base.pri)
+
+V8_GENERATED_SOURCES_DIR = generated
+
+!contains(QT_CONFIG, static): DEFINES += V8_SHARED BUILDING_V8_SHARED
+
+# this maybe removed in future
+DEFINES += ENABLE_DEBUGGER_SUPPORT
+
+# this is needed by crankshaft ( http://code.google.com/p/v8/issues/detail?id=1271 )
+DEFINES += ENABLE_VMSTATE_TRACKING ENABLE_LOGGING_AND_PROFILING
+
+CONFIG(debug, debug|release) {
+ DEFINES += DEBUG V8_ENABLE_CHECKS OBJECT_PRINT ENABLE_DISASSEMBLER
+} else {
+ DEFINES += NDEBUG
+}
+
+V8SRC = $$V8DIR/src
+
+INCLUDEPATH += \
+ $$V8SRC
+
+SOURCES += \
+ $$V8SRC/accessors.cc \
+ $$V8SRC/allocation.cc \
+ $$V8SRC/api.cc \
+ $$V8SRC/assembler.cc \
+ $$V8SRC/ast.cc \
+ $$V8SRC/atomicops_internals_x86_gcc.cc \
+ $$V8SRC/bignum.cc \
+ $$V8SRC/bignum-dtoa.cc \
+ $$V8SRC/bootstrapper.cc \
+ $$V8SRC/builtins.cc \
+ $$V8SRC/cached-powers.cc \
+ $$V8SRC/checks.cc \
+ $$V8SRC/circular-queue.cc \
+ $$V8SRC/code-stubs.cc \
+ $$V8SRC/codegen.cc \
+ $$V8SRC/compilation-cache.cc \
+ $$V8SRC/compiler.cc \
+ $$V8SRC/contexts.cc \
+ $$V8SRC/conversions.cc \
+ $$V8SRC/counters.cc \
+ $$V8SRC/cpu-profiler.cc \
+ $$V8SRC/data-flow.cc \
+ $$V8SRC/dateparser.cc \
+ $$V8SRC/debug-agent.cc \
+ $$V8SRC/debug.cc \
+ $$V8SRC/deoptimizer.cc \
+ $$V8SRC/disassembler.cc \
+ $$V8SRC/diy-fp.cc \
+ $$V8SRC/dtoa.cc \
+ $$V8SRC/execution.cc \
+ $$V8SRC/factory.cc \
+ $$V8SRC/flags.cc \
+ $$V8SRC/frame-element.cc \
+ $$V8SRC/frames.cc \
+ $$V8SRC/full-codegen.cc \
+ $$V8SRC/func-name-inferrer.cc \
+ $$V8SRC/gdb-jit.cc \
+ $$V8SRC/global-handles.cc \
+ $$V8SRC/fast-dtoa.cc \
+ $$V8SRC/fixed-dtoa.cc \
+ $$V8SRC/handles.cc \
+ $$V8SRC/hashmap.cc \
+ $$V8SRC/heap-profiler.cc \
+ $$V8SRC/heap.cc \
+ $$V8SRC/hydrogen.cc \
+ $$V8SRC/hydrogen-instructions.cc \
+ $$V8SRC/ic.cc \
+ $$V8SRC/inspector.cc \
+ $$V8SRC/interpreter-irregexp.cc \
+ $$V8SRC/isolate.cc \
+ $$V8SRC/jsregexp.cc \
+ $$V8SRC/lithium-allocator.cc \
+ $$V8SRC/lithium.cc \
+ $$V8SRC/liveedit.cc \
+ $$V8SRC/liveobjectlist.cc \
+ $$V8SRC/log-utils.cc \
+ $$V8SRC/log.cc \
+ $$V8SRC/mark-compact.cc \
+ $$V8SRC/messages.cc \
+ $$V8SRC/objects.cc \
+ $$V8SRC/objects-printer.cc \
+ $$V8SRC/objects-visiting.cc \
+ $$V8SRC/parser.cc \
+ $$V8SRC/preparser.cc \
+ $$V8SRC/preparse-data.cc \
+ $$V8SRC/profile-generator.cc \
+ $$V8SRC/property.cc \
+ $$V8SRC/regexp-macro-assembler-irregexp.cc \
+ $$V8SRC/regexp-macro-assembler.cc \
+ $$V8SRC/regexp-stack.cc \
+ $$V8SRC/rewriter.cc \
+ $$V8SRC/runtime.cc \
+ $$V8SRC/runtime-profiler.cc \
+ $$V8SRC/safepoint-table.cc \
+ $$V8SRC/scanner-base.cc \
+ $$V8SRC/scanner.cc \
+ $$V8SRC/scopeinfo.cc \
+ $$V8SRC/scopes.cc \
+ $$V8SRC/serialize.cc \
+ $$V8SRC/snapshot-common.cc \
+ $$V8SRC/spaces.cc \
+ $$V8SRC/string-search.cc \
+ $$V8SRC/string-stream.cc \
+ $$V8SRC/strtod.cc \
+ $$V8SRC/stub-cache.cc \
+ $$V8SRC/token.cc \
+ $$V8SRC/top.cc \
+ $$V8SRC/type-info.cc \
+ $$V8SRC/unicode.cc \
+ $$V8SRC/utils.cc \
+ $$V8SRC/v8-counters.cc \
+ $$V8SRC/v8.cc \
+ $$V8SRC/v8threads.cc \
+ $$V8SRC/variables.cc \
+ $$V8SRC/version.cc \
+ $$V8SRC/zone.cc \
+ $$V8SRC/extensions/gc-extension.cc \
+ $$V8SRC/extensions/externalize-string-extension.cc
+
+SOURCES += \
+ $$V8SRC/snapshot-empty.cc \
+
+arch_arm {
+DEFINES += V8_TARGET_ARCH_ARM
+SOURCES += \
+ $$V8SRC/arm/builtins-arm.cc \
+ $$V8SRC/arm/code-stubs-arm.cc \
+ $$V8SRC/arm/codegen-arm.cc \
+ $$V8SRC/arm/constants-arm.cc \
+ $$V8SRC/arm/cpu-arm.cc \
+ $$V8SRC/arm/debug-arm.cc \
+ $$V8SRC/arm/deoptimizer-arm.cc \
+ $$V8SRC/arm/disasm-arm.cc \
+ $$V8SRC/arm/frames-arm.cc \
+ $$V8SRC/arm/full-codegen-arm.cc \
+ $$V8SRC/arm/ic-arm.cc \
+ $$V8SRC/arm/lithium-arm.cc \
+ $$V8SRC/arm/lithium-codegen-arm.cc \
+ $$V8SRC/arm/lithium-gap-resolver-arm.cc \
+ $$V8SRC/arm/macro-assembler-arm.cc \
+ $$V8SRC/arm/regexp-macro-assembler-arm.cc \
+ $$V8SRC/arm/stub-cache-arm.cc \
+ $$V8SRC/arm/assembler-arm.cc
+}
+
+arch_i386 {
+DEFINES += V8_TARGET_ARCH_IA32
+SOURCES += \
+ $$V8SRC/ia32/assembler-ia32.cc \
+ $$V8SRC/ia32/builtins-ia32.cc \
+ $$V8SRC/ia32/code-stubs-ia32.cc \
+ $$V8SRC/ia32/codegen-ia32.cc \
+ $$V8SRC/ia32/cpu-ia32.cc \
+ $$V8SRC/ia32/debug-ia32.cc \
+ $$V8SRC/ia32/deoptimizer-ia32.cc \
+ $$V8SRC/ia32/disasm-ia32.cc \
+ $$V8SRC/ia32/frames-ia32.cc \
+ $$V8SRC/ia32/full-codegen-ia32.cc \
+ $$V8SRC/ia32/ic-ia32.cc \
+ $$V8SRC/ia32/lithium-codegen-ia32.cc \
+ $$V8SRC/ia32/lithium-gap-resolver-ia32.cc \
+ $$V8SRC/ia32/lithium-ia32.cc \
+ $$V8SRC/ia32/macro-assembler-ia32.cc \
+ $$V8SRC/ia32/regexp-macro-assembler-ia32.cc \
+ $$V8SRC/ia32/stub-cache-ia32.cc
+}
+
+# FIXME Should we use QT_CONFIG instead? What about 32 bit Macs?
+arch_x86_64 {
+DEFINES += V8_TARGET_ARCH_X64
+SOURCES += \
+ $$V8SRC/x64/assembler-x64.cc \
+ $$V8SRC/x64/builtins-x64.cc \
+ $$V8SRC/x64/code-stubs-x64.cc \
+ $$V8SRC/x64/codegen-x64.cc \
+ $$V8SRC/x64/cpu-x64.cc \
+ $$V8SRC/x64/debug-x64.cc \
+ $$V8SRC/x64/deoptimizer-x64.cc \
+ $$V8SRC/x64/disasm-x64.cc \
+ $$V8SRC/x64/frames-x64.cc \
+ $$V8SRC/x64/full-codegen-x64.cc \
+ $$V8SRC/x64/ic-x64.cc \
+ $$V8SRC/x64/lithium-codegen-x64.cc \
+ $$V8SRC/x64/lithium-gap-resolver-x64.cc \
+ $$V8SRC/x64/lithium-x64.cc \
+ $$V8SRC/x64/macro-assembler-x64.cc \
+ $$V8SRC/x64/regexp-macro-assembler-x64.cc \
+ $$V8SRC/x64/stub-cache-x64.cc
+}
+
+unix:!symbian:!macx {
+SOURCES += \
+ $$V8SRC/platform-linux.cc \
+ $$V8SRC/platform-posix.cc
+}
+
+#os:macos
+macx {
+SOURCES += \
+ $$V8SRC/platform-macos.cc \
+ $$V8SRC/platform-posix.cc
+}
+
+win32 {
+SOURCES += \
+ $$V8SRC/platform-win32.cc
+LIBS += Ws2_32.lib Winmm.lib
+win32-msvc*: QMAKE_CXXFLAGS += -wd4100 -wd 4291 -wd4351 -wd4355 -wd4800
+win32-msvc*:arch_i386: DEFINES += _USE_32BIT_TIME_T
+}
+
+#mode:debug
+CONFIG(debug) {
+ SOURCES += \
+ $$V8SRC/objects-debug.cc \
+ $$V8SRC/prettyprinter.cc \
+ $$V8SRC/regexp-macro-assembler-tracer.cc
+}
+
+V8_LIBRARY_FILES = \
+ $$V8SRC/runtime.js \
+ $$V8SRC/v8natives.js \
+ $$V8SRC/array.js \
+ $$V8SRC/string.js \
+ $$V8SRC/uri.js \
+ $$V8SRC/math.js \
+ $$V8SRC/messages.js \
+ $$V8SRC/apinatives.js \
+ $$V8SRC/date.js \
+ $$V8SRC/regexp.js \
+ $$V8SRC/json.js \
+ $$V8SRC/liveedit-debugger.js \
+ $$V8SRC/mirror-debugger.js \
+ $$V8SRC/debug-debugger.js
+
+v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp $$V8_GENERATED_SOURCES_DIR/libraries-empty.cpp CORE
+v8_js2c.commands += $$V8SRC/macros.py ${QMAKE_FILE_IN}
+v8_js2c.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp
+v8_js2c.input = V8_LIBRARY_FILES
+v8_js2c.variable_out = SOURCES
+v8_js2c.dependency_type = TYPE_C
+v8_js2c.depends = $$V8DIR/tools/js2c.py $$V8SRC/macros.py
+v8_js2c.CONFIG += combine
+v8_js2c.name = generating[v8] ${QMAKE_FILE_IN}
+silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands
+QMAKE_EXTRA_COMPILERS += v8_js2c
diff --git a/src/v8/v8.pro b/src/v8/v8.pro
new file mode 100644
index 0000000000..eb14ca9a19
--- /dev/null
+++ b/src/v8/v8.pro
@@ -0,0 +1,24 @@
+load(qt_module)
+
+TARGET = QtV8
+QPRO_PWD = $$PWD
+QT =
+
+CONFIG += module
+MODULE_PRI = ../modules/qt_v8.pri
+
+win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+
+load(qt_module_config)
+
+# Remove includepaths that were added by qt_module_config.
+# These cause compilation of V8 to fail because they appear before
+# 3rdparty/v8/src; 3rdparty/v8/src/v8.h will then be "shadowed" by
+# the public v8.h API header (they are not the same!).
+INCLUDEPATH -= $$MODULE_PRIVATE_INCLUDES
+INCLUDEPATH -= $$MODULE_PRIVATE_INCLUDES/$$TARGET
+INCLUDEPATH -= $$MODULE_INCLUDES $$MODULE_INCLUDES/..
+
+HEADERS += $$QT_SOURCE_TREE/src/v8/qtv8version.h
+
+include(v8.pri)
diff --git a/src/v8/v8base.pri b/src/v8/v8base.pri
new file mode 100644
index 0000000000..f0d7c00451
--- /dev/null
+++ b/src/v8/v8base.pri
@@ -0,0 +1,19 @@
+V8DIR = $$(V8DIR)
+isEmpty(V8DIR) {
+ V8DIR = $$PWD/../3rdparty/v8
+} else {
+ message(using external V8 from $$V8DIR)
+}
+
+*-g++*: {
+ QMAKE_CFLAGS_WARN_ON += -Wno-unused-parameter
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
+
+ # mksnapshot hangs if gcc 4.5 is used
+ # for reference look at http://code.google.com/p/v8/issues/detail?id=884
+ equals(QT_GCC_MAJOR_VERSION, 4): equals(QT_GCC_MINOR_VERSION, 5) {
+ message(because of a bug in gcc / v8 we need to add -fno-strict-aliasing)
+ QMAKE_CFLAGS += -fno-strict-aliasing
+ QMAKE_CXXFLAGS += -fno-strict-aliasing
+ }
+}
diff --git a/sync.profile b/sync.profile
index c830612cd3..e0d23ac3bf 100644
--- a/sync.profile
+++ b/sync.profile
@@ -4,6 +4,7 @@
"QtPrintSupport" => "$basedir/src/printsupport",
"QtOpenGL" => "$basedir/src/opengl",
"QtCore" => "$basedir/src/corelib",
+ "QtV8" => "$basedir/src/v8",
"QtXml" => "$basedir/src/xml",
"QtSql" => "$basedir/src/sql",
"QtNetwork" => "$basedir/src/network",
@@ -14,6 +15,10 @@
"QtPlatformSupport" => "$basedir/src/platformsupport",
);
%moduleheaders = ( # restrict the module headers to those found in relative path
+ "QtV8" => "../3rdparty/v8/include",
+);
+@allmoduleheadersprivate = (
+ "QtV8"
);
%classnames = (
"qglobal.h" => "QtGlobal",
@@ -38,6 +43,7 @@
"qtopenvgversion.h" => "QtOpenVGVersion",
"qtsqlversion.h" => "QtSqlVersion",
"qttestversion.h" => "QtTestVersion",
+ "qtv8version.h" => "QtV8Version",
"qtxmlversion.h" => "QtXmlVersion",
);
%mastercontent = (
@@ -61,6 +67,7 @@
"QtOpenGL" => "$basedir/src/modules/qt_opengl.pri",
"QtSql" => "$basedir/src/modules/qt_sql.pri",
"QtTest" => "$basedir/src/modules/qt_testlib.pri",
+ "QtV8" => "$basedir/src/modules/qt_v8.pri",
"QtXml" => "$basedir/src/modules/qt_xml.pri",
"QtUiTools" => "$basedir/src/modules/qt_uitools.pri",
"QtDesigner" => "$basedir/src/modules/qt_uilib.pri",
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 02e8b5bebb..fc51280c35 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -11,3 +11,4 @@ SUBDIRS += \
!cross_compile: SUBDIRS += host.pro
contains(QT_CONFIG, opengl): SUBDIRS += opengl.pro
unix:!embedded:contains(QT_CONFIG, dbus): SUBDIRS += dbus.pro
+contains(QT_CONFIG, v8): SUBDIRS += v8.pro
diff --git a/tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp
index 1b4d770ac6..98a559af85 100644
--- a/tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp
+++ b/tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp
@@ -1834,6 +1834,18 @@ void tst_QMatrixNxN::inverted4x4_data()
QTest::newRow("invertible")
<< (void *)invertible.v << (void *)inverted.v << true;
+ static Matrix4 const invertible2 = {
+ {1.0f, 2.0f, 4.0f, 2.0f,
+ 8.0f, 3.0f, 5.0f, 3.0f,
+ 6.0f, 7.0f, 9.0f, 4.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f}
+ };
+ static Matrix4 inverted2;
+ m4Inverse(invertible2, inverted2);
+
+ QTest::newRow("invertible2")
+ << (void *)invertible2.v << (void *)inverted2.v << true;
+
static Matrix4 const translate = {
{1.0f, 0.0f, 0.0f, 2.0f,
0.0f, 1.0f, 0.0f, 3.0f,
@@ -1907,12 +1919,12 @@ void tst_QMatrixNxN::orthonormalInverse4x4()
m2.rotate(45.0, 1.0, 0.0, 0.0);
m2.translate(10.0, 0.0, 0.0);
- // Use optimize() to drop the internal flags that
+ // Use operator() to drop the internal flags that
// mark the matrix as orthonormal. This will force inverted()
// to compute m3.inverted() the long way. We can then compare
// the result to what the faster algorithm produces on m2.
QMatrix4x4 m3 = m2;
- m3.optimize();
+ m3(0, 0);
bool invertible;
QVERIFY(qFuzzyCompare(m2.inverted(&invertible), m3.inverted()));
QVERIFY(invertible);
@@ -1920,7 +1932,7 @@ void tst_QMatrixNxN::orthonormalInverse4x4()
QMatrix4x4 m4;
m4.rotate(45.0, 0.0, 1.0, 0.0);
QMatrix4x4 m5 = m4;
- m5.optimize();
+ m5(0, 0);
QVERIFY(qFuzzyCompare(m4.inverted(), m5.inverted()));
QMatrix4x4 m6;
@@ -1928,7 +1940,7 @@ void tst_QMatrixNxN::orthonormalInverse4x4()
m1.translate(-20.0, 20.0, 15.0);
m1.rotate(25, 1.0, 0.0, 0.0);
QMatrix4x4 m7 = m6;
- m7.optimize();
+ m7(0, 0);
QVERIFY(qFuzzyCompare(m6.inverted(), m7.inverted()));
}
@@ -2449,6 +2461,11 @@ void tst_QMatrixNxN::normalMatrix_data()
0.0f, 7.0f, 0.0f, 5.0f,
0.0f, 0.0f, 9.0f, -3.0f,
0.0f, 0.0f, 0.0f, 1.0f};
+ static qreal const rotateValues[16] =
+ {0.0f, 0.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
static qreal const nullScaleValues1[16] =
{0.0f, 0.0f, 0.0f, 4.0f,
0.0f, 7.0f, 0.0f, 5.0f,
@@ -2468,6 +2485,7 @@ void tst_QMatrixNxN::normalMatrix_data()
QTest::newRow("translate") << (void *)translateValues;
QTest::newRow("scale") << (void *)scaleValues;
QTest::newRow("both") << (void *)bothValues;
+ QTest::newRow("rotate") << (void *)rotateValues;
QTest::newRow("null scale 1") << (void *)nullScaleValues1;
QTest::newRow("null scale 2") << (void *)nullScaleValues2;
QTest::newRow("null scale 3") << (void *)nullScaleValues3;
@@ -2844,11 +2862,13 @@ void tst_QMatrixNxN::convertGeneric()
// Copy of "flagBits" in qmatrix4x4.h.
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
};
// Structure that allows direct access to "flagBits" for testing.
@@ -2886,17 +2906,73 @@ void tst_QMatrixNxN::optimize_data()
0.0f, 0.0f, 1.0f, 4.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
- QTest::newRow("scale")
+ QTest::newRow("translate")
<< (void *)translateValues << (int)Translation;
- static qreal bothValues[16] = {
+ static qreal scaleTranslateValues[16] = {
1.0f, 0.0f, 0.0f, 2.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 4.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
- QTest::newRow("both")
- << (void *)bothValues << (int)(Scale | Translation);
+ QTest::newRow("scaleTranslate")
+ << (void *)scaleTranslateValues << (int)(Scale | Translation);
+
+ static qreal rotateValues[16] = {
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("rotate")
+ << (void *)rotateValues << (int)Rotation2D;
+
+ // Left-handed system, not a simple rotation.
+ static qreal scaleRotateValues[16] = {
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("scaleRotate")
+ << (void *)scaleRotateValues << (int)(Scale | Rotation2D);
+
+ static qreal matrix2x2Values[16] = {
+ 1.0f, 2.0f, 0.0f, 0.0f,
+ 8.0f, 3.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 9.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("matrix2x2")
+ << (void *)matrix2x2Values << (int)(Scale | Rotation2D);
+
+ static qreal matrix3x3Values[16] = {
+ 1.0f, 2.0f, 4.0f, 0.0f,
+ 8.0f, 3.0f, 5.0f, 0.0f,
+ 6.0f, 7.0f, 9.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("matrix3x3")
+ << (void *)matrix3x3Values << (int)(Scale | Rotation2D | Rotation);
+
+ static qreal rotateTranslateValues[16] = {
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, 0.0f, 0.0f, 2.0f,
+ 0.0f, 0.0f, 1.0f, 3.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("rotateTranslate")
+ << (void *)rotateTranslateValues << (int)(Translation | Rotation2D);
+
+ // Left-handed system, not a simple rotation.
+ static qreal scaleRotateTranslateValues[16] = {
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 2.0f,
+ 0.0f, 0.0f, 1.0f, 3.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ QTest::newRow("scaleRotateTranslate")
+ << (void *)scaleRotateTranslateValues << (int)(Translation | Scale | Rotation2D);
static qreal belowValues[16] = {
1.0f, 0.0f, 0.0f, 0.0f,
@@ -3240,7 +3316,6 @@ void tst_QMatrixNxN::mapVector()
QFETCH(void *, mValues);
QMatrix4x4 m1((const qreal *)mValues);
- m1.optimize();
QVector3D v(3.5f, -1.0f, 2.5f);
@@ -3250,10 +3325,15 @@ void tst_QMatrixNxN::mapVector()
v.x() * m1(2, 0) + v.y() * m1(2, 1) + v.z() * m1(2, 2));
QVector3D actual = m1.mapVector(v);
+ m1.optimize();
+ QVector3D actual2 = m1.mapVector(v);
QVERIFY(fuzzyCompare(actual.x(), expected.x()));
QVERIFY(fuzzyCompare(actual.y(), expected.y()));
QVERIFY(fuzzyCompare(actual.z(), expected.z()));
+ QVERIFY(fuzzyCompare(actual2.x(), expected.x()));
+ QVERIFY(fuzzyCompare(actual2.y(), expected.y()));
+ QVERIFY(fuzzyCompare(actual2.z(), expected.z()));
}
class tst_QMatrixNxN4x4Properties : public QObject
diff --git a/tests/auto/v8.pro b/tests/auto/v8.pro
new file mode 100644
index 0000000000..226ff7b118
--- /dev/null
+++ b/tests/auto/v8.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+ v8
diff --git a/tests/auto/v8/Makefile.nonqt b/tests/auto/v8/Makefile.nonqt
new file mode 100644
index 0000000000..ded1ba3a74
--- /dev/null
+++ b/tests/auto/v8/Makefile.nonqt
@@ -0,0 +1,16 @@
+V8PATH = ../../../src/3rdparty/v8
+V8LIBPATH = $(V8PATH)
+V8INCPATH = $(V8PATH)/include
+SOURCES = v8main.cpp v8test.cpp
+
+release-m32:
+ g++ -o v8test_release_m32 -m32 -O2 -I$(V8INCPATH) $(SOURCES) -lpthread -L$(V8LIBPATH) -lv8
+
+debug-m32:
+ g++ -o v8test_debug_m32 -m32 -g -I$(V8INCPATH) $(SOURCES) -lpthread -L$(V8LIBPATH) -lv8_g
+
+release:
+ g++ -o v8test_release -O2 -I$(V8INCPATH) $(SOURCES) -lpthread -L$(V8LIBPATH) -lv8
+
+debug:
+ g++ -o v8test_debug -g -I$(V8INCPATH) $(SOURCES) -lpthread -L$(V8LIBPATH) -lv8_g
diff --git a/tests/auto/v8/README.txt b/tests/auto/v8/README.txt
new file mode 100644
index 0000000000..097c459036
--- /dev/null
+++ b/tests/auto/v8/README.txt
@@ -0,0 +1,13 @@
+The v8 tests are actually implemented in v8test.[h|cpp]. There are also QtTest
+(tst_v8.cpp) and non-Qt (v8main.cpp) stubs provided to run these tests. This
+is done to allow the tests to be run both in the Qt CI system, and manually
+without a build of Qt. The latter is necessary to run them against more exotic
+build of V8, like the ARM simulator.
+
+To build the non-Qt version of the tests, first build a debug or release V8
+library under src/3rdparty/v8 using scons, and then use the Makefile.nonqt
+makefile selecting one of the following targets:
+ release: Build the tests with -O2 and link against libv8
+ debug: Build the tests with -g and link against libv8_g
+ release-m32: Build the tests with -O2 -m32 and link against libv8
+ debug-m32: Build the tests with -g -m32 and link against libv8_g
diff --git a/tests/auto/v8/tst_v8.cpp b/tests/auto/v8/tst_v8.cpp
new file mode 100644
index 0000000000..4ff80067c5
--- /dev/null
+++ b/tests/auto/v8/tst_v8.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <private/v8.h>
+#include "v8test.h"
+
+using namespace v8;
+
+class tst_v8 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_v8() {}
+
+private slots:
+ void initTestCase() {}
+ void cleanupTestCase() {}
+
+ void eval();
+ void userobjectcompare();
+};
+
+void tst_v8::eval()
+{
+ QVERIFY(v8test_eval());
+}
+
+void tst_v8::userobjectcompare()
+{
+ QVERIFY(v8test_userobjectcompare());
+}
+
+int main(int argc, char *argv[])
+{
+ V8::SetFlagsFromCommandLine(&argc, argv, true);
+
+ QCoreApplication app(argc, argv);
+ tst_v8 tc;
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_v8.moc"
diff --git a/tests/auto/v8/v8.pro b/tests/auto/v8/v8.pro
new file mode 100644
index 0000000000..feda53bf50
--- /dev/null
+++ b/tests/auto/v8/v8.pro
@@ -0,0 +1,9 @@
+load(qttest_p4)
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_v8.cpp v8test.cpp
+HEADERS += v8test.h
+
+CONFIG += parallel_test
+
+QT += v8-private
diff --git a/tests/auto/v8/v8main.cpp b/tests/auto/v8/v8main.cpp
new file mode 100644
index 0000000000..fa0137938e
--- /dev/null
+++ b/tests/auto/v8/v8main.cpp
@@ -0,0 +1,17 @@
+#include "v8test.h"
+#include <stdio.h>
+
+#define RUN_TEST(testname) { \
+ if (!v8test_ ## testname()) \
+ printf ("Test %s FAILED\n", # testname); \
+}
+
+int main(int argc, char *argv[])
+{
+ v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
+
+ RUN_TEST(eval);
+ RUN_TEST(userobjectcompare);
+
+ return -1;
+}
diff --git a/tests/auto/v8/v8test.cpp b/tests/auto/v8/v8test.cpp
new file mode 100644
index 0000000000..a712bf12b4
--- /dev/null
+++ b/tests/auto/v8/v8test.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "v8test.h"
+
+using namespace v8;
+
+#define BEGINTEST() bool _testPassed = true;
+#define ENDTEST() return _testPassed;
+
+#define VERIFY(expr) { \
+ if (!(expr)) { \
+ fprintf(stderr, "FAIL: %s:%d %s\n", __FILE__, __LINE__, # expr); \
+ _testPassed = false; \
+ goto cleanup; \
+ } \
+}
+
+
+bool v8test_eval()
+{
+ BEGINTEST();
+
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ Context::Scope context_scope(context);
+
+ Local<Object> qmlglobal = Object::New();
+ qmlglobal->Set(String::New("a"), Integer::New(1922));
+
+ Local<Script> script = Script::Compile(String::New("eval(\"a\")"), NULL, NULL,
+ Handle<String>(), Script::QmlMode);
+
+ TryCatch tc;
+ Local<Value> result = script->Run(qmlglobal);
+
+ VERIFY(!tc.HasCaught());
+ VERIFY(result->Int32Value() == 1922);
+
+cleanup:
+ context.Dispose();
+
+ ENDTEST();
+}
+
+static int userObjectComparisonCalled = 0;
+static bool userObjectComparisonReturn = false;
+static Local<Object> expectedLhs;
+static Local<Object> expectedRhs;
+static bool expectedObjectsCompared = false;
+
+#define SET_EXPECTED(lhs, rhs) { \
+ expectedObjectsCompared = false; \
+ expectedLhs = lhs; \
+ expectedRhs = rhs; \
+}
+
+static bool UserObjectComparison(Local<Object> lhs, Local<Object> rhs)
+{
+ userObjectComparisonCalled++;
+
+ expectedObjectsCompared = (lhs == expectedLhs && rhs == expectedRhs);
+
+ return userObjectComparisonReturn;
+}
+
+inline bool runscript(const char *source) {
+ Local<Script> script = Script::Compile(String::New(source));
+ Local<Value> result = script->Run();
+ return result->BooleanValue();
+}
+
+bool v8test_userobjectcompare()
+{
+ BEGINTEST();
+
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ Context::Scope context_scope(context);
+
+ V8::SetUserObjectComparisonCallbackFunction(UserObjectComparison);
+
+ Local<ObjectTemplate> ot = ObjectTemplate::New();
+ ot->MarkAsUseUserObjectComparison();
+
+ Local<Object> uoc1 = ot->NewInstance();
+ Local<Object> uoc2 = ot->NewInstance();
+ context->Global()->Set(String::New("uoc1a"), uoc1);
+ context->Global()->Set(String::New("uoc1b"), uoc1);
+ context->Global()->Set(String::New("uoc2"), uoc2);
+ Local<Object> obj1 = Object::New();
+ context->Global()->Set(String::New("obj1a"), obj1);
+ context->Global()->Set(String::New("obj1b"), obj1);
+ context->Global()->Set(String::New("obj2"), Object::New());
+ Local<String> string1 = String::New("Hello World");
+ context->Global()->Set(String::New("string1a"), string1);
+ context->Global()->Set(String::New("string1b"), string1);
+ context->Global()->Set(String::New("string2"), v8::String::New("Goodbye World"));
+
+ // XXX Opportunity for optimization - don't invoke user callback if objects are
+ // equal.
+#if 0
+ userObjectComparisonCalled = 0; userObjectComparisonReturn = false;
+ VERIFY(true == runscript("uoc1a == uoc1b"));
+ VERIFY(userObjectComparisonCalled == 0);
+#endif
+
+ // Comparing two uoc objects invokes uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(false == runscript("uoc1a == uoc2"));
+ VERIFY(userObjectComparisonCalled == 1);
+
+ VERIFY(false == runscript("uoc2 == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 2);
+ userObjectComparisonReturn = true;
+ VERIFY(true == runscript("uoc1a == uoc2"));
+ VERIFY(userObjectComparisonCalled == 3);
+ VERIFY(true == runscript("uoc2 == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 4);
+
+ // != on two uoc object invokes uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(true == runscript("uoc1a != uoc2"));
+ VERIFY(userObjectComparisonCalled == 1);
+ VERIFY(true == runscript("uoc2 != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 2);
+ userObjectComparisonReturn = true;
+ VERIFY(false == runscript("uoc1a != uoc2"));
+ VERIFY(userObjectComparisonCalled == 3);
+ VERIFY(false == runscript("uoc2 != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 4);
+
+ // Comparison against a non-object doesn't invoke uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(false == runscript("uoc1a == string1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+ VERIFY(false == runscript("string1a == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+ VERIFY(false == runscript("2 == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+ VERIFY(true == runscript("uoc1a != string1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+ VERIFY(true == runscript("string1a != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+ VERIFY(true == runscript("2 != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 0);
+
+ // Comparison against a non-uoc-object still invokes uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(false == runscript("uoc1a == obj1a"));
+ VERIFY(userObjectComparisonCalled == 1);
+ VERIFY(false == runscript("obj1a == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 2);
+ userObjectComparisonReturn = true;
+ VERIFY(true == runscript("uoc1a == obj1a"));
+ VERIFY(userObjectComparisonCalled == 3);
+ VERIFY(true == runscript("obj1a == uoc1a"));
+ VERIFY(userObjectComparisonCalled == 4);
+
+ // != comparison against a non-uoc-object still invokes uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(true == runscript("uoc1a != obj1a"));
+ VERIFY(userObjectComparisonCalled == 1);
+ VERIFY(true == runscript("obj1a != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 2);
+ userObjectComparisonReturn = true;
+ VERIFY(false == runscript("uoc1a != obj1a"));
+ VERIFY(userObjectComparisonCalled == 3);
+ VERIFY(false == runscript("obj1a != uoc1a"));
+ VERIFY(userObjectComparisonCalled == 4);
+
+ // Comparing two non-uoc objects does not invoke uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ VERIFY(true == runscript("obj1a == obj1a"));
+ VERIFY(true == runscript("obj1a == obj1b"));
+ VERIFY(false == runscript("obj1a == obj2"));
+ VERIFY(false == runscript("obj1a == string1a"));
+ VERIFY(true == runscript("string1a == string1a"));
+ VERIFY(true == runscript("string1a == string1b"));
+ VERIFY(false == runscript("string1a == string2"));
+ VERIFY(userObjectComparisonCalled == 0);
+
+ // Correct lhs and rhs passed to uoc
+ userObjectComparisonCalled = 0;
+ userObjectComparisonReturn = false;
+ SET_EXPECTED(uoc1, uoc2);
+ VERIFY(false == runscript("uoc1a == uoc2"));
+ VERIFY(true == expectedObjectsCompared);
+ SET_EXPECTED(uoc2, uoc1);
+ VERIFY(false == runscript("uoc2 == uoc1a"));
+ VERIFY(true == expectedObjectsCompared);
+ SET_EXPECTED(uoc1, uoc2);
+ VERIFY(true == runscript("uoc1a != uoc2"));
+ VERIFY(true == expectedObjectsCompared);
+ SET_EXPECTED(uoc2, uoc1);
+ VERIFY(true == runscript("uoc2 != uoc1a"));
+ VERIFY(true == expectedObjectsCompared);
+ SET_EXPECTED(uoc1, obj1);
+ VERIFY(false == runscript("uoc1a == obj1a"));
+ VERIFY(true == expectedObjectsCompared);
+ SET_EXPECTED(obj1, uoc1);
+ VERIFY(false == runscript("obj1a == uoc1a"));
+ VERIFY(true == expectedObjectsCompared);
+
+cleanup:
+ V8::SetUserObjectComparisonCallbackFunction(0);
+ context.Dispose();
+
+ ENDTEST();
+}
diff --git a/tests/auto/v8/v8test.h b/tests/auto/v8/v8test.h
new file mode 100644
index 0000000000..812036dd66
--- /dev/null
+++ b/tests/auto/v8/v8test.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef V8TEST_H
+#define V8TEST_H
+
+#ifdef QT_CORE_LIB
+#include <private/v8.h>
+#else
+#include <v8.h>
+#endif
+
+bool v8test_eval();
+bool v8test_userobjectcompare();
+
+#endif // V8TEST_H
+
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp
index e980755305..eafc6690c8 100644
--- a/tools/configure/configureapp.cpp
+++ b/tools/configure/configureapp.cpp
@@ -282,6 +282,7 @@ Configure::Configure(int& argc, char** argv)
dictionary[ "WMSDK" ] = "auto";
dictionary[ "DIRECTSHOW" ] = "no";
dictionary[ "WEBKIT" ] = "auto";
+ dictionary[ "V8" ] = "auto";
dictionary[ "DECLARATIVE" ] = "auto";
dictionary[ "DECLARATIVE_DEBUG" ]= "yes";
dictionary[ "PLUGIN_MANIFESTS" ] = "yes";
@@ -991,6 +992,10 @@ void Configure::parseCmdLine()
dictionary[ "WEBKIT" ] = "yes";
} else if (configCmdLine.at(i) == "-webkit-debug") {
dictionary[ "WEBKIT" ] = "debug";
+ } else if (configCmdLine.at(i) == "-no-v8") {
+ dictionary[ "V8" ] = "no";
+ } else if (configCmdLine.at(i) == "-v8") {
+ dictionary[ "V8" ] = "yes";
} else if (configCmdLine.at(i) == "-no-declarative") {
dictionary[ "DECLARATIVE" ] = "no";
} else if (configCmdLine.at(i) == "-declarative") {
@@ -1876,6 +1881,8 @@ bool Configure::displayHelp()
desc("SCRIPT", "yes", "-script", "Build the QtScript module.");
desc("SCRIPTTOOLS", "no", "-no-scripttools", "Do not build the QtScriptTools module.");
desc("SCRIPTTOOLS", "yes", "-scripttools", "Build the QtScriptTools module.");
+ desc("V8", "no", "-no-v8", "Do not build the V8 module.");
+ desc("V8", "yes", "-v8", "Build the V8 module.");
desc("DECLARATIVE", "no", "-no-declarative", "Do not build the declarative module");
desc("DECLARATIVE", "yes", "-declarative", "Build the declarative module");
desc("DECLARATIVE_DEBUG", "no", "-no-declarative-debug", "Do not build the declarative debugging support");
@@ -2190,7 +2197,7 @@ bool Configure::checkAvailability(const QString &part)
}
} else if (part == "WMSDK") {
available = findFile("wmsdk.h");
- } else if (part == "MULTIMEDIA" || part == "SCRIPT" || part == "SCRIPTTOOLS" || part == "DECLARATIVE") {
+ } else if (part == "MULTIMEDIA" || part == "SCRIPT" || part == "SCRIPTTOOLS" || part == "V8" || part == "DECLARATIVE") {
available = true;
} else if (part == "WEBKIT") {
available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-msvc2010") || (dictionary.value("QMAKESPEC") == "win32-g++");
@@ -2333,8 +2340,10 @@ void Configure::autoDetection()
dictionary["PHONON"] = checkAvailability("PHONON") ? "yes" : "no";
if (dictionary["WEBKIT"] == "auto")
dictionary["WEBKIT"] = checkAvailability("WEBKIT") ? "yes" : "no";
+ if (dictionary["V8"] == "auto")
+ dictionary["V8"] = checkAvailability("V8") ? "yes" : "no";
if (dictionary["DECLARATIVE"] == "auto")
- dictionary["DECLARATIVE"] = dictionary["SCRIPT"] == "yes" ? "yes" : "no";
+ dictionary["DECLARATIVE"] = dictionary["V8"] == "yes" ? "yes" : "no";
if (dictionary["DECLARATIVE_DEBUG"] == "auto")
dictionary["DECLARATIVE_DEBUG"] = dictionary["DECLARATIVE"] == "yes" ? "yes" : "no";
if (dictionary["AUDIO_BACKEND"] == "auto")
@@ -2392,9 +2401,9 @@ bool Configure::verifyConfiguration()
if (!(l.contains(dictionary["ARM_FPU_TYPE"])))
cout << QString("WARNING: Using unsupported fpu flag: %1").arg(dictionary["ARM_FPU_TYPE"]) << endl;
}
- if (dictionary["DECLARATIVE"] == "yes" && dictionary["SCRIPT"] == "no") {
+ if (dictionary["DECLARATIVE"] == "yes" && dictionary["V8"] == "no") {
cout << "WARNING: To be able to compile QtDeclarative we need to also compile the" << endl
- << "QtScript module. If you continue, we will turn on the QtScript module." << endl
+ << "V8 module. If you continue, we will turn on the V8 module." << endl
<< "(Press any key to continue..)";
if (_getch() == 3) // _Any_ keypress w/no echo(eat <Enter> for stdout)
exit(0); // Exit cleanly for Ctrl+C
@@ -2754,8 +2763,8 @@ void Configure::generateOutputVars()
// No longer needed after modularization
// if (dictionary["DECLARATIVE"] == "yes") {
-// if (dictionary[ "SCRIPT" ] == "no") {
-// cout << "QtDeclarative was requested, but it can't be built due to QtScript being "
+// if (dictionary[ "V8" ] == "no") {
+// cout << "QtDeclarative was requested, but it can't be built due to V8 being "
// "disabled." << endl;
// dictionary[ "DONE" ] = "error";
// }
@@ -3186,6 +3195,7 @@ void Configure::generateConfigfiles()
if (dictionary["OPENSSL"] == "linked") qconfigList += "QT_LINKED_OPENSSL";
if (dictionary["DBUS"] == "no") qconfigList += "QT_NO_DBUS";
if (dictionary["WEBKIT"] == "no") qconfigList += "QT_NO_WEBKIT";
+ if (dictionary["V8"] == "no") qconfigList += "QT_NO_V8";
if (dictionary["DECLARATIVE"] == "no") qconfigList += "QT_NO_DECLARATIVE";
if (dictionary["DECLARATIVE_DEBUG"] == "no") qconfigList += "QDECLARATIVE_NO_DEBUG_PROTOCOL";
if (dictionary["PHONON"] == "no") qconfigList += "QT_NO_PHONON";
@@ -3480,6 +3490,7 @@ void Configure::displayConfig()
if (declarative == "yes")
cout << "Declarative debugging......." << dictionary[ "DECLARATIVE_DEBUG" ] << endl;
}
+ cout << "V8 support.................." << dictionary[ "V8" ] << endl;
cout << "QtScript support............" << dictionary[ "SCRIPT" ] << endl;
cout << "QtScriptTools support......." << dictionary[ "SCRIPTTOOLS" ] << endl;
cout << "Graphics System............." << dictionary[ "GRAPHICS_SYSTEM" ] << endl;