Merge remote branch 'gerrit/master' into refactor
Conflicts: src/src.pro Change-Id: Ic04fb170b82e86dc3cef6fe979f8fb709db10daf
This commit is contained in:
commit
42f2da5e6b
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "src/3rdparty/v8"]
|
||||
path = src/3rdparty/v8
|
||||
url = git://github.com/aaronkennedy/v8.git
|
@ -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) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
SOURCES = fontconfig.cpp
|
||||
CONFIG += x11
|
||||
CONFIG -= qt
|
||||
LIBS += -lfreetype -lfontconfig
|
||||
include(../../unix/freetype/freetype.pri)
|
||||
|
30
configure
vendored
30
configure
vendored
@ -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"
|
||||
|
1
src/3rdparty/v8
vendored
Submodule
1
src/3rdparty/v8
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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]);
|
||||
|
16
src/modules/qt_v8.pri
Normal file
16
src/modules/qt_v8.pri
Normal file
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
118
src/v8/0002-Add-a-bit-field-3-to-Map.patch
Normal file
118
src/v8/0002-Add-a-bit-field-3-to-Map.patch
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
894
src/v8/0004-Generalize-external-object-resources.patch
Normal file
894
src/v8/0004-Generalize-external-object-resources.patch
Normal file
@ -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
|
||||
|
1777
src/v8/0005-Introduce-a-QML-compilation-mode.patch
Normal file
1777
src/v8/0005-Introduce-a-QML-compilation-mode.patch
Normal file
File diff suppressed because it is too large
Load Diff
48
src/v8/0006-Allow-access-to-the-calling-script-data.patch
Normal file
48
src/v8/0006-Allow-access-to-the-calling-script-data.patch
Normal file
@ -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
|
||||
|
46
src/v8/0007-Fix-warnings.patch
Normal file
46
src/v8/0007-Fix-warnings.patch
Normal file
@ -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
|
||||
|
489
src/v8/0008-Add-custom-object-compare-callback.patch
Normal file
489
src/v8/0008-Add-custom-object-compare-callback.patch
Normal file
@ -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, ¬_user_equal);
|
||||
+
|
||||
+ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
|
||||
+ __ b(ne, ¬_user_equal);
|
||||
+
|
||||
+ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
|
||||
+ __ b(ne, ¬_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, ¬_user_equal);
|
||||
+
|
||||
+ __ bind(&user_equal);
|
||||
+
|
||||
+ __ Push(r0, r1);
|
||||
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
|
||||
+
|
||||
+ __ bind(¬_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, ¬_user_equal);
|
||||
+ __ test(edx, Immediate(kSmiTagMask));
|
||||
+ __ j(zero, ¬_user_equal);
|
||||
+
|
||||
+ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
|
||||
+ __ j(not_equal, ¬_user_equal);
|
||||
+
|
||||
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
|
||||
+ __ j(not_equal, ¬_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(¬_user_equal);
|
||||
+
|
||||
+ __ bind(&user_equal);
|
||||
+
|
||||
+ __ pop(ebx); // Return address.
|
||||
+ __ push(eax);
|
||||
+ __ push(edx);
|
||||
+ __ push(ebx);
|
||||
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
|
||||
+
|
||||
+ __ bind(¬_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, ¬_user_equal);
|
||||
+ __ JumpIfSmi(rdx, ¬_user_equal);
|
||||
+
|
||||
+ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
|
||||
+ __ j(not_equal, ¬_user_equal);
|
||||
+
|
||||
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
|
||||
+ __ j(not_equal, ¬_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(¬_user_equal);
|
||||
+
|
||||
+ __ bind(&user_equal);
|
||||
+
|
||||
+ __ pop(rbx); // Return address.
|
||||
+ __ push(rax);
|
||||
+ __ push(rdx);
|
||||
+ __ push(rbx);
|
||||
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
|
||||
+
|
||||
+ __ bind(¬_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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
116
src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch
Normal file
116
src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch
Normal file
@ -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
|
||||
|
15
src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch
Normal file
15
src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch
Normal file
@ -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
|
||||
|
1
src/v8/README
Normal file
1
src/v8/README
Normal file
@ -0,0 +1 @@
|
||||
These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2
|
260
src/v8/v8.pri
Normal file
260
src/v8/v8.pri
Normal file
@ -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
|
24
src/v8/v8.pro
Normal file
24
src/v8/v8.pro
Normal file
@ -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)
|
19
src/v8/v8base.pri
Normal file
19
src/v8/v8base.pri
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
3
tests/auto/v8.pro
Normal file
3
tests/auto/v8.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
v8
|
16
tests/auto/v8/Makefile.nonqt
Normal file
16
tests/auto/v8/Makefile.nonqt
Normal file
@ -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
|
13
tests/auto/v8/README.txt
Normal file
13
tests/auto/v8/README.txt
Normal file
@ -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
|
80
tests/auto/v8/tst_v8.cpp
Normal file
80
tests/auto/v8/tst_v8.cpp
Normal file
@ -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"
|
9
tests/auto/v8/v8.pro
Normal file
9
tests/auto/v8/v8.pro
Normal file
@ -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
|
17
tests/auto/v8/v8main.cpp
Normal file
17
tests/auto/v8/v8main.cpp
Normal file
@ -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;
|
||||
}
|
254
tests/auto/v8/v8test.cpp
Normal file
254
tests/auto/v8/v8test.cpp
Normal file
@ -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();
|
||||
}
|
55
tests/auto/v8/v8test.h
Normal file
55
tests/auto/v8/v8test.h
Normal file
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user