Add QtV8 library to QtBase

This adds Aaron's copy of V8 to src/3rdparty/v8 (as a
git submodule), and builds it as a "normal" Qt library
(without any dependencies on Qt itself).

The library can be added to a project with

QT += v8-private

V8 API headers are available as private includes, e.g.

 #include <private/v8.h>

The API is private because we're exposing a third-party
API directly, and we don't want to (and cannot) make
source or binary compatibility guarantees for it.

Since we want the V8 public API headers to be private
headers in Qt, syncqt and sync.profile were extended to
understand a new configuration option, the
@allmoduleheadersprivate array, that tells syncqt whether
all the library headers should be treated as private even
though they don't follow the _p.h Qt convention.

The V8 project files, patches and autotests are copied
from the QtDeclarative repository. The next step after
this commit is to remove QtDeclarative's copy of V8 and
link with QtV8 instead.

Task-number: QTBUG-20963
Change-Id: Ib8820362cdbc8fa662a5e97db841656cf38d1b62
Reviewed-on: http://codereview.qt.nokia.com/3092
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
This commit is contained in:
Kent Hansen 2011-08-16 10:50:00 +02:00 committed by Qt by Nokia
parent 13b3545e83
commit 9830cb8e59
34 changed files with 5790 additions and 10 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "src/3rdparty/v8"]
path = src/3rdparty/v8
url = git://github.com/aaronkennedy/v8.git

View File

@ -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) {

30
configure vendored
View File

@ -708,6 +708,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)
@ -2123,6 +2124,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"
@ -3897,6 +3909,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.
@ -7618,9 +7633,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
@ -8670,6 +8695,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

@ -0,0 +1 @@
Subproject commit dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44

16
src/modules/qt_v8.pri Normal file
View 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

View File

@ -8,6 +8,7 @@ SRC_SUBDIRS += src_corelib src_network src_sql src_testlib src_xml src_uitools
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
!wince*:!symbian-abld:!symbian-sbsv2:include(tools/tools.pro)
@ -27,6 +28,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

View File

@ -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

View 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

View File

@ -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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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, &not_user_equal);
+
+ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
+ __ b(ne, &not_user_equal);
+
+ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
+ __ b(ne, &not_user_equal);
+
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &user_equal);
+
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset));
+ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(ne, &not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ Push(r0, r1);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ tst(r2, Operand(kSmiTagMask));
__ b(eq, &miss);
- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
+ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss);
- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
+ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
ASSERT(GetCondition() == eq);
__ sub(r0, r0, Operand(r1));
diff --git a/src/factory.cc b/src/factory.cc
index d530a75..6f8c7de 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
int internal_field_count = 0;
bool has_external_resource = false;
+ bool use_user_object_comparison = false;
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
@@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
Smi::cast(instance_template->internal_field_count())->value();
has_external_resource =
!instance_template->has_external_resource()->IsUndefined();
+ use_user_object_comparison =
+ !instance_template->use_user_object_comparison()->IsUndefined();
}
int instance_size = kPointerSize * internal_field_count;
@@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
map->set_has_external_resource(true);
}
+ // Mark as using user object comparison if needed
+ if (use_user_object_comparison) {
+ map->set_use_user_object_comparison(true);
+ }
+
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index afa599e..0964ab9 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ Assert(not_zero, "Unexpected smi operands.");
}
+ {
+ NearLabel not_user_equal, user_equal;
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &not_user_equal);
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &not_user_equal);
+
+ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
+ __ j(not_equal, &not_user_equal);
+
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &not_user_equal);
+
+ __ test_b(FieldOperand(ebx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal);
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal);
+
+ __ jmp(&not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ pop(ebx); // Return address.
+ __ push(eax);
+ __ push(edx);
+ __ push(ebx);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
+
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, not_taken);
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss);
__ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, not_taken);
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss);
ASSERT(GetCondition() == equal);
__ sub(eax, Operand(edx));
diff --git a/src/isolate.h b/src/isolate.h
index 35ffcb4..8130397 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED {
// Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_;
+ // Call back function for user object comparisons
+ v8::UserObjectComparisonCallback user_object_comparison_callback_;
+
private:
void InitializeInternal();
@@ -699,6 +702,11 @@ class Isolate {
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
+ void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback);
+ inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() {
+ return thread_local_top()->user_object_comparison_callback_;
+ }
+
// Exception throwing support. The caller should use the result
// of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 1c7f83e..1765441 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2552,6 +2552,19 @@ bool Map::has_external_resource()
}
+void Map::set_use_user_object_comparison(bool value) {
+ if (value) {
+ set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison));
+ } else {
+ set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison));
+ }
+}
+
+bool Map::use_user_object_comparison() {
+ return ((1 << kUseUserObjectComparison) & bit_field3()) != 0;
+}
+
+
void Map::set_named_interceptor_is_fallback(bool value)
{
if (value) {
@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset)
ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
kHasExternalResourceOffset)
+ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
+ kUseUserObjectComparisonOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
diff --git a/src/objects.h b/src/objects.h
index edbc47a..e75e9f1 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -3724,6 +3724,11 @@ class Map: public HeapObject {
inline void set_has_external_resource(bool value);
inline bool has_external_resource();
+
+ // Tells whether the user object comparison callback should be used for
+ // comparisons involving this object
+ inline void set_use_user_object_comparison(bool value);
+ inline bool use_user_object_comparison();
// Whether the named interceptor is a fallback interceptor or not
inline void set_named_interceptor_is_fallback(bool value);
@@ -3922,6 +3927,7 @@ class Map: public HeapObject {
// Bit positions for bit field 3
static const int kNamedInterceptorIsFallback = 0;
static const int kHasExternalResource = 1;
+ static const int kUseUserObjectComparison = 2;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo {
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
DECL_ACCESSORS(has_external_resource, Object)
+ DECL_ACCESSORS(use_user_object_comparison, Object)
static inline ObjectTemplateInfo* cast(Object* obj);
@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
- static const int kSize = kHasExternalResourceOffset + kPointerSize;
+ static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize;
+ static const int kSize = kUseUserObjectComparisonOffset + kPointerSize;
};
diff --git a/src/runtime.cc b/src/runtime.cc
index 827d954..d552ddb 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+
+ CONVERT_CHECKED(JSObject, lhs, args[1]);
+ CONVERT_CHECKED(JSObject, rhs, args[0]);
+
+ bool result;
+
+ v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
+ if (callback) {
+ HandleScope scope(isolate);
+ Handle<JSObject> lhs_handle(lhs);
+ Handle<JSObject> rhs_handle(rhs);
+ result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
+ } else {
+ result = (lhs == rhs);
+ }
+
+ return Smi::FromInt(result?0:1);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
diff --git a/src/runtime.h b/src/runtime.h
index 5e97173..0d754f9 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -146,6 +146,7 @@ namespace internal {
/* Comparisons */ \
F(NumberEquals, 2, 1) \
F(StringEquals, 2, 1) \
+ F(UserObjectEquals, 2, 1) \
\
F(NumberCompare, 3, 1) \
F(SmiLexicographicCompare, 2, 1) \
diff --git a/src/top.cc b/src/top.cc
index e078ee9..c345383 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() {
thread_id_ = ThreadId::Invalid();
external_caught_exception_ = false;
failed_access_check_callback_ = NULL;
+ user_object_comparison_callback_ = NULL;
save_context_ = NULL;
catcher_ = NULL;
}
@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback(
thread_local_top()->failed_access_check_callback_ = callback;
}
+void Isolate::SetUserObjectComparisonCallback(
+ v8::UserObjectComparisonCallback callback) {
+ thread_local_top()->user_object_comparison_callback_ = callback;
+}
void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
if (!thread_local_top()->failed_access_check_callback_) return;
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index d923494..10b9b56 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
__ bind(&ok);
}
+ {
+ NearLabel not_user_equal, user_equal;
+ __ JumpIfSmi(rax, &not_user_equal);
+ __ JumpIfSmi(rdx, &not_user_equal);
+
+ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
+ __ j(not_equal, &not_user_equal);
+
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &not_user_equal);
+
+ __ testb(FieldOperand(rbx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal);
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal);
+
+ __ jmp(&not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ pop(rbx); // Return address.
+ __ push(rax);
+ __ push(rdx);
+ __ push(rbx);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
// The compare stub returns a positive, negative, or zero 64-bit integer
// value in rax, corresponding to result of comparing the two inputs.
// NOTICE! This code is only reached after a smi-fast-case check, so
@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, not_taken);
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss);
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, not_taken);
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss);
ASSERT(GetCondition() == equal);
__ subq(rax, rdx);
--
1.7.2.3

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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
View File

@ -0,0 +1 @@
These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2

260
src/v8/v8.pri Normal file
View 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
View 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
View 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
}
}

View File

@ -3,6 +3,7 @@
"QtOpenGL" => "$basedir/src/opengl",
"QtOpenVG" => "$basedir/src/openvg",
"QtCore" => "$basedir/src/corelib",
"QtV8" => "$basedir/src/v8",
"QtXml" => "$basedir/src/xml",
"QtSql" => "$basedir/src/sql",
"QtNetwork" => "$basedir/src/network",
@ -12,6 +13,10 @@
"QtDesigner" => "$basedir/tools/uilib",
);
%moduleheaders = ( # restrict the module headers to those found in relative path
"QtV8" => "../3rdparty/v8/include",
);
@allmoduleheadersprivate = (
"QtV8"
);
%classnames = (
"qglobal.h" => "QtGlobal",
@ -36,6 +41,7 @@
"qtopenvgversion.h" => "QtOpenVGVersion",
"qtsqlversion.h" => "QtSqlVersion",
"qttestversion.h" => "QtTestVersion",
"qtv8version.h" => "QtV8Version",
"qtxmlversion.h" => "QtXmlVersion",
);
%mastercontent = (
@ -57,6 +63,7 @@
"QtOpenVG" => "$basedir/src/modules/qt_openvg.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",

View File

@ -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

3
tests/auto/v8.pro Normal file
View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = \
v8

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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;