diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..183f5b46cc1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/3rdparty/v8"] + path = src/3rdparty/v8 + url = git://github.com/aaronkennedy/v8.git diff --git a/bin/syncqt b/bin/syncqt index 4eab929b309..f28b2bf60a1 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -33,7 +33,7 @@ $qtbasedir = dirname(dirname($0)) if (!$qtbasedir); $qtbasedir =~ s=\\=/=g if (defined $qtbasedir); # will be defined based on the modules sync.profile -our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris); +our (%modules, %moduleheaders, @allmoduleheadersprivate, %classnames, %mastercontent, %modulepris); # global variables (modified by options) my $isunix = 0; @@ -792,6 +792,8 @@ loadSyncProfile(\$basedir, \$out_basedir); @modules_to_sync = keys(%modules) if($#modules_to_sync == -1); +my %allmoduleheadersprivate = map { $_ => 1 } @allmoduleheadersprivate; + $isunix = checkUnix; #cache checkUnix # create path @@ -828,6 +830,9 @@ foreach my $lib (@modules_to_sync) { my $pathtoheaders = ""; $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib}); + my $allheadersprivate = 0; + $allheadersprivate = 1 if $allmoduleheadersprivate{$lib}; + #information used after the syncing my $pri_install_classes = ""; my $pri_install_files = ""; @@ -955,7 +960,7 @@ foreach my $lib (@modules_to_sync) { my $header_copies = 0; #figure out if it is a public header my $public_header = $header; - if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) { + if($allheadersprivate || $public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) { $public_header = 0; } else { foreach (@ignore_for_master_contents) { diff --git a/configure b/configure index 0a18aafd8ce..35ffeee6a09 100755 --- a/configure +++ b/configure @@ -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" diff --git a/src/3rdparty/v8 b/src/3rdparty/v8 new file mode 160000 index 00000000000..dc2cad4f8fc --- /dev/null +++ b/src/3rdparty/v8 @@ -0,0 +1 @@ +Subproject commit dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44 diff --git a/src/modules/qt_v8.pri b/src/modules/qt_v8.pri new file mode 100644 index 00000000000..89d6c263e86 --- /dev/null +++ b/src/modules/qt_v8.pri @@ -0,0 +1,16 @@ +QT.v8.VERSION = 5.0.0 +QT.v8.MAJOR_VERSION = 5 +QT.v8.MINOR_VERSION = 0 +QT.v8.PATCH_VERSION = 0 + +QT.v8.name = QtV8 +QT.v8.bins = $$QT_MODULE_BIN_BASE +QT.v8.includes = $$QT_MODULE_INCLUDE_BASE/QtV8 +QT.v8.private_includes = $$QT_MODULE_INCLUDE_BASE/QtV8/$$QT.v8.VERSION +QT.v8.sources = $$QT_MODULE_BASE/src/v8 +QT.v8.libs = $$QT_MODULE_LIB_BASE +QT.v8.plugins = $$QT_MODULE_PLUGIN_BASE +QT.v8.imports = $$QT_MODULE_IMPORT_BASE +QT.v8.depends = +QT.v8.DEFINES = +!contains(QT_CONFIG, static): QT.v8.DEFINES += V8_SHARED USING_V8_SHARED diff --git a/src/src.pro b/src/src.pro index 491973c6353..caac6426f35 100644 --- a/src/src.pro +++ b/src/src.pro @@ -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 diff --git a/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch new file mode 100644 index 00000000000..54a35fda9fe --- /dev/null +++ b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch @@ -0,0 +1,343 @@ +From e13ce09287a56c920d5ffdc5d4662d49f1838f16 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 15:47:20 +1000 +Subject: [PATCH 01/13] Add hashing and comparison methods to v8::String + +This allows us to more rapidly search for a v8::String inside +a hash of QStrings. +--- + include/v8.h | 44 ++++++++++++++++++++++++++++++ + src/api.cc | 43 +++++++++++++++++++++++++++++ + src/heap-inl.h | 2 + + src/heap.cc | 3 ++ + src/objects-inl.h | 1 + + src/objects.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + src/objects.h | 15 +++++++++- + 7 files changed, 182 insertions(+), 3 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index d15d024..bbd29e9 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -994,6 +994,48 @@ class String : public Primitive { + V8EXPORT int Utf8Length() const; + + /** ++ * Returns the hash of this string. ++ */ ++ V8EXPORT uint32_t Hash() const; ++ ++ struct CompleteHashData { ++ CompleteHashData() : length(0), hash(0), symbol_id(0) {} ++ int length; ++ uint32_t hash; ++ uint32_t symbol_id; ++ }; ++ ++ /** ++ * Returns the "complete" hash of the string. This is ++ * all the information about the string needed to implement ++ * a very efficient hash keyed on the string. ++ * ++ * The members of CompleteHashData are: ++ * length: The length of the string. Equivalent to Length() ++ * hash: The hash of the string. Equivalent to Hash() ++ * symbol_id: If the string is a sequential symbol, the symbol ++ * id, otherwise 0. If the symbol ids of two strings are ++ * the same (and non-zero) the two strings are identical. ++ * If the symbol ids are different the strings may still be ++ * identical, but an Equals() check must be performed. ++ */ ++ V8EXPORT CompleteHashData CompleteHash() const; ++ ++ /** ++ * Compute a hash value for the passed UTF16 string ++ * data. ++ */ ++ V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length); ++ V8EXPORT static uint32_t ComputeHash(char *string, int length); ++ ++ /** ++ * Returns true if this string is equal to the external ++ * string data provided. ++ */ ++ V8EXPORT bool Equals(uint16_t *string, int length); ++ V8EXPORT bool Equals(char *string, int length); ++ ++ /** + * Write the contents of the string to an external buffer. + * If no arguments are given, expects the buffer to be large + * enough to hold the entire string and NULL terminator. Copies +@@ -1023,6 +1065,8 @@ class String : public Primitive { + HINT_MANY_WRITES_EXPECTED = 1 + }; + ++ V8EXPORT uint16_t GetCharacter(int index); ++ + V8EXPORT int Write(uint16_t* buffer, + int start = 0, + int length = -1, +diff --git a/src/api.cc b/src/api.cc +index a2373cd..381935b 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3284,6 +3284,49 @@ int String::Utf8Length() const { + return str->Utf8Length(); + } + ++uint32_t String::Hash() const { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0; ++ return str->Hash(); ++} ++ ++String::CompleteHashData String::CompleteHash() const { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData(); ++ CompleteHashData result; ++ result.length = str->length(); ++ result.hash = str->Hash(); ++ if (str->IsSeqString()) ++ result.symbol_id = i::SeqString::cast(*str)->symbol_id(); ++ return result; ++} ++ ++uint32_t String::ComputeHash(uint16_t *string, int length) { ++ return i::HashSequentialString(string, length) >> i::String::kHashShift; ++} ++ ++uint32_t String::ComputeHash(char *string, int length) { ++ return i::HashSequentialString(string, length) >> i::String::kHashShift; ++} ++ ++uint16_t String::GetCharacter(int index) ++{ ++ i::Handle str = Utils::OpenHandle(this); ++ return str->Get(index); ++} ++ ++bool String::Equals(uint16_t *string, int length) { ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} ++ ++bool String::Equals(char *string, int length) ++{ ++ i::Handle str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} + + int String::WriteUtf8(char* buffer, + int capacity, +diff --git a/src/heap-inl.h b/src/heap-inl.h +index 99737ed..f4fce7b 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -93,6 +93,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +diff --git a/src/heap.cc b/src/heap.cc +index 2b6c11f..930c97b 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, + String* answer = String::cast(result); + answer->set_length(chars); + answer->set_hash_field(hash_field); ++ SeqString::cast(result)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { + HeapObject::cast(result)->set_map(ascii_string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +@@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length, + HeapObject::cast(result)->set_map(string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 65aec5d..c82080d 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset) + + + SMI_ACCESSORS(String, length, kLengthOffset) ++SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset) + + + uint32_t String::hash_field() { +diff --git a/src/objects.cc b/src/objects.cc +index df61956..dc4b260 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate, + } + } + ++bool String::SlowEqualsExternal(uc16 *string, int length) { ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (lhs->IsFlat()) { ++ if (lhs->IsAsciiRepresentation()) { ++ Vector vec1 = lhs->ToAsciiVector(); ++ VectorIterator buf1(vec1); ++ VectorIterator ib(string, length); ++ return CompareStringContents(&buf1, &ib); ++ } else { ++ Vector vec1 = lhs->ToUC16Vector(); ++ Vector vec2(string, length); ++ return CompareRawStringContents(vec1, vec2); ++ } ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} ++ ++bool String::SlowEqualsExternal(char *string, int length) ++{ ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (StringShape(lhs).IsSequentialAscii()) { ++ const char* str1 = SeqAsciiString::cast(lhs)->GetChars(); ++ return CompareRawStringContents(Vector(str1, len), ++ Vector(string, len)); ++ } ++ ++ if (lhs->IsFlat()) { ++ Vector vec1 = lhs->ToUC16Vector(); ++ VectorIterator buf1(vec1); ++ VectorIterator buf2(string, length); ++ return CompareStringContents(&buf1, &buf2); ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} + + bool String::SlowEquals(String* other) { + // Fast check: negative check with lengths. +@@ -8655,9 +8715,24 @@ class AsciiSymbolKey : public SequentialSymbolKey { + + MaybeObject* AsObject() { + if (hash_field_ == 0) Hash(); +- return HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) { ++ while (true) { ++ Atomic32 my_symbol_id = next_symbol_id; ++ if (my_symbol_id > Smi::kMaxValue) ++ break; ++ if (my_symbol_id == NoBarrier_CompareAndSwap(&next_symbol_id, my_symbol_id, my_symbol_id + 1)) { ++ SeqString::cast(result->ToObjectUnchecked())->set_symbol_id(my_symbol_id); ++ break; ++ } ++ } ++ } ++ return result; + } ++ ++ static Atomic32 next_symbol_id; + }; ++Atomic32 AsciiSymbolKey::next_symbol_id = 1; + + + class TwoByteSymbolKey : public SequentialSymbolKey { +diff --git a/src/objects.h b/src/objects.h +index e966b3d..6e26f57 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -5359,6 +5359,9 @@ class String: public HeapObject { + bool IsAsciiEqualTo(Vector str); + bool IsTwoByteEqualTo(Vector str); + ++ bool SlowEqualsExternal(uc16 *string, int length); ++ bool SlowEqualsExternal(char *string, int length); ++ + // Return a UTF8 representation of the string. The string is null + // terminated but may optionally contain nulls. Length is returned + // in length_output if length_output is not a null pointer The string +@@ -5610,9 +5613,17 @@ class String: public HeapObject { + class SeqString: public String { + public: + ++ // Get and set the symbol id of the string ++ inline int symbol_id(); ++ inline void set_symbol_id(int value); ++ + // Casting. + static inline SeqString* cast(Object* obj); + ++ // Layout description. ++ static const int kSymbolIdOffset = String::kSize; ++ static const int kSize = kSymbolIdOffset + kPointerSize; ++ + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); + }; +@@ -5647,7 +5658,7 @@ class SeqAsciiString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential ASCII string. +@@ -5701,7 +5712,7 @@ class SeqTwoByteString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential two-byte string. +-- +1.7.2.3 + diff --git a/src/v8/0002-Add-a-bit-field-3-to-Map.patch b/src/v8/0002-Add-a-bit-field-3-to-Map.patch new file mode 100644 index 00000000000..dda9fa0dffe --- /dev/null +++ b/src/v8/0002-Add-a-bit-field-3-to-Map.patch @@ -0,0 +1,118 @@ +From 7c9cfff80b7864d5687432d424074e51712c4a07 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 15:55:26 +1000 +Subject: [PATCH 02/13] Add a bit field 3 to Map + +Bit field 3 will be used to add QML specific map flags. +--- + src/heap.cc | 2 ++ + src/objects-inl.h | 10 ++++++++++ + src/objects.cc | 2 ++ + src/objects.h | 9 ++++++++- + 4 files changed, 22 insertions(+), 1 deletions(-) + +diff --git a/src/heap.cc b/src/heap.cc +index 930c97b..900f462 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -1573,6 +1573,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, + reinterpret_cast(result)->set_unused_property_fields(0); + reinterpret_cast(result)->set_bit_field(0); + reinterpret_cast(result)->set_bit_field2(0); ++ reinterpret_cast(result)->set_bit_field3(0); + return result; + } + +@@ -1599,6 +1600,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { + map->set_unused_property_fields(0); + map->set_bit_field(0); + map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements)); ++ map->set_bit_field3(0); + + // If the map object is aligned fill the padding area with Smi 0 objects. + if (Map::kPadStart < Map::kSize) { +diff --git a/src/objects-inl.h b/src/objects-inl.h +index c82080d..cce3edd 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2430,6 +2430,16 @@ void Map::set_bit_field2(byte value) { + } + + ++byte Map::bit_field3() { ++ return READ_BYTE_FIELD(this, kBitField3Offset); ++} ++ ++ ++void Map::set_bit_field3(byte value) { ++ WRITE_BYTE_FIELD(this, kBitField3Offset, value); ++} ++ ++ + void Map::set_non_instance_prototype(bool value) { + if (value) { + set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); +diff --git a/src/objects.cc b/src/objects.cc +index dc4b260..79d7240 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -3614,6 +3614,7 @@ MaybeObject* Map::CopyDropDescriptors() { + } + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + Map::cast(result)->set_is_shared(false); + Map::cast(result)->ClearCodeCache(heap); + return result; +@@ -3642,6 +3643,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, + + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + + Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); + +diff --git a/src/objects.h b/src/objects.h +index 6e26f57..07e1089 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -3597,6 +3597,10 @@ class Map: public HeapObject { + inline byte bit_field2(); + inline void set_bit_field2(byte value); + ++ // Bit field 3. ++ inline byte bit_field3(); ++ inline void set_bit_field3(byte value); ++ + // Tells whether the object in the prototype property will be used + // for instances created from this function. If the prototype + // property is set to a value that is not a JSObject, the prototype +@@ -3844,7 +3848,7 @@ class Map: public HeapObject { + // Layout description. + static const int kInstanceSizesOffset = HeapObject::kHeaderSize; + static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; +- static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; ++ static const int kPrototypeOffset = POINTER_SIZE_ALIGN(kInstanceAttributesOffset + 2 * kIntSize); + static const int kConstructorOffset = kPrototypeOffset + kPointerSize; + static const int kInstanceDescriptorsOffset = + kConstructorOffset + kPointerSize; +@@ -3876,6 +3880,7 @@ class Map: public HeapObject { + static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1; + static const int kBitFieldOffset = kInstanceAttributesOffset + 2; + static const int kBitField2Offset = kInstanceAttributesOffset + 3; ++ static const int kBitField3Offset = kInstanceAttributesOffset + 4; + + STATIC_CHECK(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset); + +@@ -3898,6 +3903,8 @@ class Map: public HeapObject { + static const int kIsShared = 5; + static const int kHasExternalArrayElements = 6; + ++ // Bit positions for bit field 3 ++ + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; + static const int kCodeCacheEntryNameOffset = 0; +-- +1.7.2.3 + diff --git a/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch new file mode 100644 index 00000000000..50f97c7de8d --- /dev/null +++ b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch @@ -0,0 +1,364 @@ +From ae8688b53d67044f2c9b0cce25fc282b078610c1 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 16:21:02 +1000 +Subject: [PATCH 03/13] Add a "fallback" mode for named property interceptors + +By default interceptors are called before the normal property +resolution on objects. When an interceptor is installed as a +"fallback" interceptor, it is only called if the object doesn't +already have the property. + +In the case of a global object having an fallback interceptor, +the interceptor is not invoked at all for var or function +declarations. +--- + include/v8.h | 8 ++++++++ + src/api.cc | 29 +++++++++++++++++++++++++++++ + src/factory.cc | 4 ++++ + src/handles.cc | 6 ++++-- + src/handles.h | 3 ++- + src/objects-inl.h | 16 ++++++++++++++++ + src/objects.cc | 22 ++++++++++++++++------ + src/objects.h | 18 ++++++++++++++---- + src/runtime.cc | 11 ++++++----- + 9 files changed, 99 insertions(+), 18 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index bbd29e9..85452aa 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2169,6 +2169,7 @@ class V8EXPORT FunctionTemplate : public Template { + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle data); + void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, + IndexedPropertySetter setter, +@@ -2253,6 +2254,13 @@ class V8EXPORT ObjectTemplate : public Template { + NamedPropertyEnumerator enumerator = 0, + Handle data = Handle()); + ++ void SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter = 0, ++ NamedPropertyQuery query = 0, ++ NamedPropertyDeleter deleter = 0, ++ NamedPropertyEnumerator enumerator = 0, ++ Handle data = Handle()); ++ + /** + * Sets an indexed property handler on the object template. + * +diff --git a/src/api.cc b/src/api.cc +index 381935b..8b0b32a 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle data) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + if (IsDeadCheck(isolate, +@@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); + if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); + if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); ++ obj->set_is_fallback(i::Smi::FromInt(is_fallback)); + + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); +@@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, + query, + remover, + enumerator, ++ false, ++ data); ++} ++ ++ ++void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter, ++ NamedPropertyQuery query, ++ NamedPropertyDeleter remover, ++ NamedPropertyEnumerator enumerator, ++ Handle data) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ EnsureConstructor(this); ++ i::FunctionTemplateInfo* constructor = ++ i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); ++ i::Handle cons(constructor); ++ Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter, ++ setter, ++ query, ++ remover, ++ enumerator, ++ true, + data); + } + +diff --git a/src/factory.cc b/src/factory.cc +index 7dee66f..dcdc645 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -1058,6 +1058,10 @@ Handle Factory::CreateApiFunction( + // Set interceptor information in the map. + if (!obj->named_property_handler()->IsUndefined()) { + map->set_has_named_interceptor(); ++ ++ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler()); ++ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value(); ++ map->set_named_interceptor_is_fallback(is_fallback); + } + if (!obj->indexed_property_handler()->IsUndefined()) { + map->set_has_indexed_interceptor(); +diff --git a/src/handles.cc b/src/handles.cc +index 326de86..dd3a86c 100644 +--- a/src/handles.cc ++++ b/src/handles.cc +@@ -262,9 +262,11 @@ Handle SetProperty(Handle object, + Handle key, + Handle value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + CALL_HEAP_FUNCTION(object->GetIsolate(), +- object->SetProperty(*key, *value, attributes, strict_mode), ++ object->SetProperty(*key, *value, attributes, strict_mode, ++ skip_fallback_interceptor), + Object); + } + +diff --git a/src/handles.h b/src/handles.h +index 3839f37..4b42506 100644 +--- a/src/handles.h ++++ b/src/handles.h +@@ -188,7 +188,8 @@ Handle SetProperty(Handle object, + Handle key, + Handle value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + + Handle SetProperty(Handle object, + Handle key, +diff --git a/src/objects-inl.h b/src/objects-inl.h +index cce3edd..6aaca2f 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2521,6 +2521,21 @@ bool Map::is_shared() { + } + + ++void Map::set_named_interceptor_is_fallback(bool value) ++{ ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback)); ++ } ++} ++ ++bool Map::named_interceptor_is_fallback() ++{ ++ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0; ++} ++ ++ + JSFunction* Map::unchecked_constructor() { + return reinterpret_cast(READ_FIELD(this, kConstructorOffset)); + } +@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) + ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) + ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) + ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ++ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset) + + ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) + ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) +diff --git a/src/objects.cc b/src/objects.cc +index 79d7240..15e2cdb 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( + MaybeObject* JSObject::SetProperty(String* name, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + LookupResult result; +- LocalLookup(name, &result); ++ LocalLookup(name, &result, skip_fallback_interceptor); + return SetProperty(&result, name, value, attributes, strict_mode); + } + +@@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { + } + + +-void JSObject::LocalLookup(String* name, LookupResult* result) { ++void JSObject::LocalLookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + ASSERT(name->IsString()); + + Heap* heap = GetHeap(); +@@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) { + } + + // Check for lookup interceptor except when bootstrapping. +- if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { ++ bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive(); ++ if (wouldIntercept && !map()->named_interceptor_is_fallback()) { + result->InterceptorResult(this); + return; + } + + LocalLookupRealNamedProperty(name, result); ++ ++ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() && ++ map()->named_interceptor_is_fallback()) { ++ result->InterceptorResult(this); ++ return; ++ } + } + + +-void JSObject::Lookup(String* name, LookupResult* result) { ++void JSObject::Lookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + // Ecma-262 3rd 8.6.2.4 + Heap* heap = GetHeap(); + for (Object* current = this; + current != heap->null_value(); + current = JSObject::cast(current)->GetPrototype()) { +- JSObject::cast(current)->LocalLookup(name, result); ++ JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor); + if (result->IsProperty()) return; + } + result->NotFound(); +diff --git a/src/objects.h b/src/objects.h +index 07e1089..a209cd0 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1405,7 +1405,8 @@ class JSObject: public HeapObject { + MUST_USE_RESULT MaybeObject* SetProperty(String* key, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, + String* key, + Object* value, +@@ -1637,8 +1638,8 @@ class JSObject: public HeapObject { + + // Lookup a property. If found, the result is valid and has + // detailed information. +- void LocalLookup(String* name, LookupResult* result); +- void Lookup(String* name, LookupResult* result); ++ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); ++ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); + + // The following lookup functions skip interceptors. + void LocalLookupRealNamedProperty(String* name, LookupResult* result); +@@ -3714,6 +3715,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Whether the named interceptor is a fallback interceptor or not ++ inline void set_named_interceptor_is_fallback(bool value); ++ inline bool named_interceptor_is_fallback(); ++ ++ + // [prototype]: implicit prototype object. + DECL_ACCESSORS(prototype, Object) + +@@ -3904,6 +3911,7 @@ class Map: public HeapObject { + static const int kHasExternalArrayElements = 6; + + // Bit positions for bit field 3 ++ static const int kNamedInterceptorIsFallback = 0; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct { + DECL_ACCESSORS(deleter, Object) + DECL_ACCESSORS(enumerator, Object) + DECL_ACCESSORS(data, Object) ++ DECL_ACCESSORS(is_fallback, Smi) + + static inline InterceptorInfo* cast(Object* obj); + +@@ -6295,7 +6304,8 @@ class InterceptorInfo: public Struct { + static const int kDeleterOffset = kQueryOffset + kPointerSize; + static const int kEnumeratorOffset = kDeleterOffset + kPointerSize; + static const int kDataOffset = kEnumeratorOffset + kPointerSize; +- static const int kSize = kDataOffset + kPointerSize; ++ static const int kFallbackOffset = kDataOffset + kPointerSize; ++ static const int kSize = kFallbackOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); +diff --git a/src/runtime.cc b/src/runtime.cc +index 7335da8..660352c 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + // Lookup the property in the global object, and don't set the + // value of the variable if the property is already there. + LookupResult lookup; +- global->Lookup(*name, &lookup); ++ global->Lookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if the property is local by comparing the holder + // against the global object. The information will be used to +@@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + } + + LookupResult lookup; +- global->LocalLookup(*name, &lookup); ++ global->LocalLookup(*name, &lookup, true); + + PropertyAttributes attributes = is_const_property + ? static_cast(base | READ_ONLY) +@@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + name, + value, + attributes, +- strict_mode)); ++ strict_mode, ++ true)); + } + } + +@@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + JSObject* real_holder = global; + LookupResult lookup; + while (true) { +- real_holder->LocalLookup(*name, &lookup); ++ real_holder->LocalLookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if this is a redeclaration of something read-only. + if (lookup.IsReadOnly()) { +@@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + + global = isolate->context()->global(); + if (assign) { +- return global->SetProperty(*name, args[2], attributes, strict_mode); ++ return global->SetProperty(*name, args[2], attributes, strict_mode, true); + } + return isolate->heap()->undefined_value(); + } +-- +1.7.2.3 + diff --git a/src/v8/0004-Generalize-external-object-resources.patch b/src/v8/0004-Generalize-external-object-resources.patch new file mode 100644 index 00000000000..f44e7b21343 --- /dev/null +++ b/src/v8/0004-Generalize-external-object-resources.patch @@ -0,0 +1,894 @@ +From 4827116b12c50f6662794017c5a662b5dbb2da0b Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 16:55:35 +1000 +Subject: [PATCH 04/13] Generalize external object resources + +V8 was already able to manage and finalize an external string +resource. This change generalizes that mechanism to handle a +single generic external resource - a v8::Object::ExternalResource +derived instance - on normal JSObject's. + +This is useful for mapping C++ objects to JS objects where the +C++ object's memory is effectively owned by the JS Object, and +thus needs to destroyed when the JS Object is garbage collected. +The V8 mailing list suggests using a weak persistent handle for +this purpose, but that seems to incur a fairly massive performance +penalty for short lived objects as weak persistent handle callbacks +are not called until the object has been promoted into the old +object space. +--- + include/v8.h | 25 ++++++ + src/api.cc | 64 ++++++++++++++- + src/extensions/externalize-string-extension.cc | 4 +- + src/factory.cc | 11 +++ + src/heap-inl.h | 101 +++++++++++++++--------- + src/heap.cc | 68 ++++++++-------- + src/heap.h | 42 +++++----- + src/liveobjectlist.cc | 4 +- + src/mark-compact.cc | 21 +++--- + src/objects-inl.h | 41 +++++++++- + src/objects.h | 14 +++- + 11 files changed, 280 insertions(+), 115 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 85452aa..7f06ae7 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1630,6 +1630,25 @@ class Object : public Value { + /** Sets a native pointer in an internal field. */ + V8EXPORT void SetPointerInInternalField(int index, void* value); + ++ class V8EXPORT ExternalResource { // NOLINT ++ public: ++ ExternalResource() {} ++ virtual ~ExternalResource() {} ++ ++ protected: ++ virtual void Dispose() { delete this; } ++ ++ private: ++ // Disallow copying and assigning. ++ ExternalResource(const ExternalResource&); ++ void operator=(const ExternalResource&); ++ ++ friend class v8::internal::Heap; ++ }; ++ ++ V8EXPORT void SetExternalResource(ExternalResource *); ++ V8EXPORT ExternalResource *GetExternalResource(); ++ + // Testers for local properties. + V8EXPORT bool HasRealNamedProperty(Handle key); + V8EXPORT bool HasRealIndexedProperty(uint32_t index); +@@ -2331,6 +2350,12 @@ class V8EXPORT ObjectTemplate : public Template { + */ + void SetInternalFieldCount(int value); + ++ /** ++ * Sets whether the object can store an "external resource" object. ++ */ ++ bool HasExternalResource(); ++ void SetHasExternalResource(bool value); ++ + private: + ObjectTemplate(); + static Local New(Handle constructor); +diff --git a/src/api.cc b/src/api.cc +index 8b0b32a..1a6fbbb 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1294,6 +1294,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) { + } + + ++bool ObjectTemplate::HasExternalResource() ++{ ++ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(), ++ "v8::ObjectTemplate::HasExternalResource()")) { ++ return 0; ++ } ++ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined(); ++} ++ ++ ++void ObjectTemplate::SetHasExternalResource(bool value) ++{ ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ if (value) { ++ EnsureConstructor(this); ++ } ++ if (value) { ++ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1)); ++ } else { ++ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value()); ++ } ++} ++ ++ + // --- S c r i p t D a t a --- + + +@@ -3652,6 +3680,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { + } + + ++void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ENTER_V8(isolate); ++ i::Handle obj = Utils::OpenHandle(this); ++ if (CanBeEncodedAsSmi(resource)) { ++ obj->SetExternalResourceObject(EncodeAsSmi(resource)); ++ } else { ++ obj->SetExternalResourceObject(*isolate->factory()->NewProxy(static_cast((void *)resource))); ++ } ++ if (!obj->IsSymbol()) { ++ isolate->heap()->external_resource_table()->AddObject(*obj); ++ } ++} ++ ++ ++v8::Object::ExternalResource *v8::Object::GetExternalResource() { ++ i::Handle obj = Utils::OpenHandle(this); ++ i::Object* value = obj->GetExternalResourceObject(); ++ if (value->IsSmi()) { ++ return reinterpret_cast(i::Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ return reinterpret_cast(i::Proxy::cast(value)->proxy()); ++ } else { ++ return NULL; ++ } ++} ++ ++ + // --- E n v i r o n m e n t --- + + +@@ -4144,7 +4200,7 @@ Local v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle result = NewExternalStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4162,7 +4218,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +@@ -4175,7 +4231,7 @@ Local v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle result = NewExternalAsciiStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4194,7 +4250,7 @@ bool v8::String::MakeExternal( + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc +index b3f83fe..8e50904 100644 +--- a/src/extensions/externalize-string-extension.cc ++++ b/src/extensions/externalize-string-extension.cc +@@ -100,7 +100,7 @@ v8::Handle ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } else { +@@ -110,7 +110,7 @@ v8::Handle ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } +diff --git a/src/factory.cc b/src/factory.cc +index dcdc645..d530a75 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -997,15 +997,21 @@ Handle Factory::CreateApiFunction( + Handle construct_stub = isolate()->builtins()->JSConstructStubApi(); + + int internal_field_count = 0; ++ bool has_external_resource = false; ++ + if (!obj->instance_template()->IsUndefined()) { + Handle instance_template = + Handle( + ObjectTemplateInfo::cast(obj->instance_template())); + internal_field_count = + Smi::cast(instance_template->internal_field_count())->value(); ++ has_external_resource = ++ !instance_template->has_external_resource()->IsUndefined(); + } + + int instance_size = kPointerSize * internal_field_count; ++ if (has_external_resource) instance_size += kPointerSize; ++ + InstanceType type = INVALID_TYPE; + switch (instance_type) { + case JavaScriptObject: +@@ -1040,6 +1046,11 @@ Handle Factory::CreateApiFunction( + + Handle map = Handle(result->initial_map()); + ++ // Mark as having external data object if needed ++ if (has_external_resource) { ++ map->set_has_external_resource(true); ++ } ++ + // Mark as undetectable if needed. + if (obj->undetectable()) { + map->set_is_undetectable(); +diff --git a/src/heap-inl.h b/src/heap-inl.h +index f4fce7b..58e7adf 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -205,21 +205,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) { + } + + +-void Heap::FinalizeExternalString(String* string) { +- ASSERT(string->IsExternalString()); +- v8::String::ExternalStringResourceBase** resource_addr = +- reinterpret_cast( +- reinterpret_cast(string) + +- ExternalString::kResourceOffset - +- kHeapObjectTag); +- +- // Dispose of the C++ object if it has not already been disposed. +- if (*resource_addr != NULL) { +- (*resource_addr)->Dispose(); +- } ++void Heap::FinalizeExternalString(HeapObject* string) { ++ ASSERT(string->IsExternalString() || string->map()->has_external_resource()); ++ ++ if (string->IsExternalString()) { ++ v8::String::ExternalStringResourceBase** resource_addr = ++ reinterpret_cast( ++ reinterpret_cast(string) + ++ ExternalString::kResourceOffset - ++ kHeapObjectTag); ++ ++ // Dispose of the C++ object if it has not already been disposed. ++ if (*resource_addr != NULL) { ++ (*resource_addr)->Dispose(); ++ } + +- // Clear the resource pointer in the string. +- *resource_addr = NULL; ++ // Clear the resource pointer in the string. ++ *resource_addr = NULL; ++ } else { ++ JSObject *object = JSObject::cast(string); ++ Object *value = object->GetExternalResourceObject(); ++ v8::Object::ExternalResource *resource = 0; ++ if (value->IsSmi()) { ++ resource = reinterpret_cast(Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ resource = reinterpret_cast(Proxy::cast(value)->proxy()); ++ } ++ if (resource) { ++ resource->Dispose(); ++ } ++ } + } + + +@@ -556,53 +571,63 @@ inline bool Heap::allow_allocation(bool new_state) { + #endif + + +-void ExternalStringTable::AddString(String* string) { +- ASSERT(string->IsExternalString()); ++void ExternalResourceTable::AddString(String* string) { ++ ASSERT(string->IsExternalString() ); + if (heap_->InNewSpace(string)) { +- new_space_strings_.Add(string); ++ new_space_objects_.Add(string); ++ } else { ++ old_space_objects_.Add(string); ++ } ++} ++ ++ ++void ExternalResourceTable::AddObject(HeapObject* object) { ++ ASSERT(object->map()->has_external_resource()); ++ if (heap_->InNewSpace(object)) { ++ new_space_objects_.Add(object); + } else { +- old_space_strings_.Add(string); ++ old_space_objects_.Add(object); + } + } + + +-void ExternalStringTable::Iterate(ObjectVisitor* v) { +- if (!new_space_strings_.is_empty()) { +- Object** start = &new_space_strings_[0]; +- v->VisitPointers(start, start + new_space_strings_.length()); ++void ExternalResourceTable::Iterate(ObjectVisitor* v) { ++ if (!new_space_objects_.is_empty()) { ++ Object** start = &new_space_objects_[0]; ++ v->VisitPointers(start, start + new_space_objects_.length()); + } +- if (!old_space_strings_.is_empty()) { +- Object** start = &old_space_strings_[0]; +- v->VisitPointers(start, start + old_space_strings_.length()); ++ if (!old_space_objects_.is_empty()) { ++ Object** start = &old_space_objects_[0]; ++ v->VisitPointers(start, start + old_space_objects_.length()); + } + } + + + // Verify() is inline to avoid ifdef-s around its calls in release + // mode. +-void ExternalStringTable::Verify() { ++void ExternalResourceTable::Verify() { + #ifdef DEBUG +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- ASSERT(heap_->InNewSpace(new_space_strings_[i])); +- ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ ASSERT(heap_->InNewSpace(new_space_objects_[i])); ++ ASSERT(new_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ ASSERT(old_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } + #endif + } + + +-void ExternalStringTable::AddOldString(String* string) { +- ASSERT(string->IsExternalString()); +- ASSERT(!heap_->InNewSpace(string)); +- old_space_strings_.Add(string); ++void ExternalResourceTable::AddOldObject(HeapObject* object) { ++ ASSERT(object->IsExternalString() || object->map()->has_external_resource()); ++ ASSERT(!heap_->InNewSpace(object)); ++ old_space_objects_.Add(object); + } + + +-void ExternalStringTable::ShrinkNewStrings(int position) { +- new_space_strings_.Rewind(position); ++void ExternalResourceTable::ShrinkNewObjects(int position) { ++ new_space_objects_.Rewind(position); + Verify(); + } + +diff --git a/src/heap.cc b/src/heap.cc +index 900f462..bf2940e 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -155,7 +155,7 @@ Heap::Heap() + memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); + global_contexts_list_ = NULL; + mark_compact_collector_.heap_ = this; +- external_string_table_.heap_ = this; ++ external_resource_table_.heap_ = this; + } + + +@@ -1030,8 +1030,8 @@ void Heap::Scavenge() { + + new_space_front = DoScavenge(&scavenge_visitor, new_space_front); + +- UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + LiveObjectList::UpdateReferencesForScavengeGC(); + isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); +@@ -1053,38 +1053,38 @@ void Heap::Scavenge() { + } + + +-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++HeapObject* Heap::UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + MapWord first_word = HeapObject::cast(*p)->map_word(); + + if (!first_word.IsForwardingAddress()) { + // Unreachable external string can be finalized. +- heap->FinalizeExternalString(String::cast(*p)); ++ heap->FinalizeExternalString(HeapObject::cast(*p)); + return NULL; + } + + // String is still reachable. +- return String::cast(first_word.ToForwardingAddress()); ++ return HeapObject::cast(first_word.ToForwardingAddress()); + } + + +-void Heap::UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func) { +- external_string_table_.Verify(); ++void Heap::UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func) { ++ external_resource_table_.Verify(); + +- if (external_string_table_.new_space_strings_.is_empty()) return; ++ if (external_resource_table_.new_space_objects_.is_empty()) return; + +- Object** start = &external_string_table_.new_space_strings_[0]; +- Object** end = start + external_string_table_.new_space_strings_.length(); ++ Object** start = &external_resource_table_.new_space_objects_[0]; ++ Object** end = start + external_resource_table_.new_space_objects_.length(); + Object** last = start; + + for (Object** p = start; p < end; ++p) { + ASSERT(InFromSpace(*p)); +- String* target = updater_func(this, p); ++ HeapObject* target = updater_func(this, p); + + if (target == NULL) continue; + +- ASSERT(target->IsExternalString()); ++ ASSERT(target->IsExternalString() || target->map()->has_external_resource()); + + if (InNewSpace(target)) { + // String is still in new space. Update the table entry. +@@ -1092,12 +1092,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable( + ++last; + } else { + // String got promoted. Move it to the old string list. +- external_string_table_.AddOldString(target); ++ external_resource_table_.AddOldObject(target); + } + } + + ASSERT(last <= end); +- external_string_table_.ShrinkNewStrings(static_cast(last - start)); ++ external_resource_table_.ShrinkNewObjects(static_cast(last - start)); + } + + +@@ -4468,7 +4468,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { + v->Synchronize("symbol_table"); + if (mode != VISIT_ALL_IN_SCAVENGE) { + // Scavenge collections have special processing for this. +- external_string_table_.Iterate(v); ++ external_resource_table_.Iterate(v); + } + v->Synchronize("external_string_table"); + } +@@ -4970,7 +4970,7 @@ void Heap::TearDown() { + + isolate_->global_handles()->TearDown(); + +- external_string_table_.TearDown(); ++ external_resource_table_.TearDown(); + + new_space_.TearDown(); + +@@ -5835,31 +5835,31 @@ void TranscendentalCache::Clear() { + } + + +-void ExternalStringTable::CleanUp() { ++void ExternalResourceTable::CleanUp() { + int last = 0; +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- if (heap_->InNewSpace(new_space_strings_[i])) { +- new_space_strings_[last++] = new_space_strings_[i]; ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ if (new_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ if (heap_->InNewSpace(new_space_objects_[i])) { ++ new_space_objects_[last++] = new_space_objects_[i]; + } else { +- old_space_strings_.Add(new_space_strings_[i]); ++ old_space_objects_.Add(new_space_objects_[i]); + } + } +- new_space_strings_.Rewind(last); ++ new_space_objects_.Rewind(last); + last = 0; +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- old_space_strings_[last++] = old_space_strings_[i]; ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ if (old_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ old_space_objects_[last++] = old_space_objects_[i]; + } +- old_space_strings_.Rewind(last); ++ old_space_objects_.Rewind(last); + Verify(); + } + + +-void ExternalStringTable::TearDown() { +- new_space_strings_.Free(); +- old_space_strings_.Free(); ++void ExternalResourceTable::TearDown() { ++ new_space_objects_.Free(); ++ old_space_objects_.Free(); + } + + +diff --git a/src/heap.h b/src/heap.h +index ae4e9e7..8cbf378 100644 +--- a/src/heap.h ++++ b/src/heap.h +@@ -237,8 +237,8 @@ class Isolate; + class WeakObjectRetainer; + + +-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap, +- Object** pointer); ++typedef HeapObject* (*ExternalResourceTableUpdaterCallback)(Heap* heap, ++ Object** pointer); + + typedef bool (*DirtyRegionCallback)(Heap* heap, + Address start, +@@ -284,43 +284,45 @@ class PromotionQueue { + }; + + +-// External strings table is a place where all external strings are +-// registered. We need to keep track of such strings to properly +-// finalize them. +-class ExternalStringTable { ++// External resource table is a place where all external strings and ++// objects with an external resource are registered. We need to keep ++// track of such strings to properly finalize them. ++class ExternalResourceTable { + public: + // Registers an external string. + inline void AddString(String* string); ++ // Registers an external object. ++ inline void AddObject(HeapObject* object); + + inline void Iterate(ObjectVisitor* v); + + // Restores internal invariant and gets rid of collected strings. +- // Must be called after each Iterate() that modified the strings. ++ // Must be called after each Iterate() that modified the objects. + void CleanUp(); + + // Destroys all allocated memory. + void TearDown(); + + private: +- ExternalStringTable() { } ++ ExternalResourceTable() { } + + friend class Heap; + + inline void Verify(); + +- inline void AddOldString(String* string); ++ inline void AddOldObject(HeapObject* object); + + // Notifies the table that only a prefix of the new list is valid. +- inline void ShrinkNewStrings(int position); ++ inline void ShrinkNewObjects(int position); + + // To speed up scavenge collections new space string are kept + // separate from old space strings. +- List new_space_strings_; +- List old_space_strings_; ++ List new_space_objects_; ++ List old_space_objects_; + + Heap* heap_; + +- DISALLOW_COPY_AND_ASSIGN(ExternalStringTable); ++ DISALLOW_COPY_AND_ASSIGN(ExternalResourceTable); + }; + + +@@ -753,7 +755,7 @@ class Heap { + + // Finalizes an external string by deleting the associated external + // data and clearing the resource pointer. +- inline void FinalizeExternalString(String* string); ++ inline void FinalizeExternalString(HeapObject* string); + + // Allocates an uninitialized object. The memory is non-executable if the + // hardware and OS allow. +@@ -1191,8 +1193,8 @@ class Heap { + survived_since_last_expansion_ += survived; + } + +- void UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func); ++ void UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func); + + void ProcessWeakReferences(WeakObjectRetainer* retainer); + +@@ -1228,8 +1230,8 @@ class Heap { + return &mark_compact_collector_; + } + +- ExternalStringTable* external_string_table() { +- return &external_string_table_; ++ ExternalResourceTable* external_resource_table() { ++ return &external_resource_table_; + } + + inline Isolate* isolate(); +@@ -1462,7 +1464,7 @@ class Heap { + // Performs a minor collection in new generation. + void Scavenge(); + +- static String* UpdateNewSpaceReferenceInExternalStringTableEntry( ++ static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry( + Heap* heap, + Object** pointer); + +@@ -1593,7 +1595,7 @@ class Heap { + // configured through the API until it is setup. + bool configured_; + +- ExternalStringTable external_string_table_; ++ ExternalResourceTable external_resource_table_; + + bool is_safe_to_read_maps_; + +diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc +index 5795a6b..8866e58 100644 +--- a/src/liveobjectlist.cc ++++ b/src/liveobjectlist.cc +@@ -1989,7 +1989,7 @@ Object* LiveObjectList::PrintObj(int obj_id) { + ASSERT(resource->IsAscii()); + Handle dump_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*dump_string); ++ ExternalResourceTable::AddString(*dump_string); + return *dump_string; + } else { + delete resource; +@@ -2193,7 +2193,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { + ASSERT(resource->IsAscii()); + Handle path_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*path_string); ++ ExternalResourceTable::AddString(*path_string); + return *path_string; + } else { + delete resource; +diff --git a/src/mark-compact.cc b/src/mark-compact.cc +index 68a5062..1b1e361 100644 +--- a/src/mark-compact.cc ++++ b/src/mark-compact.cc +@@ -163,7 +163,7 @@ void MarkCompactCollector::Finish() { + // objects (empty string, illegal builtin). + heap()->isolate()->stub_cache()->Clear(); + +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.CleanUp(); + + // If we've just compacted old space there's no reason to check the + // fragmentation limit. Just return. +@@ -1019,8 +1019,9 @@ class SymbolTableCleaner : public ObjectVisitor { + + // Since no objects have yet been moved we can safely access the map of + // the object. +- if ((*p)->IsExternalString()) { +- heap_->FinalizeExternalString(String::cast(*p)); ++ if ((*p)->IsExternalString() || ++ (*p)->IsHeapObject() && HeapObject::cast(*p)->map()->has_external_resource()) { ++ heap_->FinalizeExternalString(HeapObject::cast(*p)); + } + // Set the entry to null_value (as deleted). + *p = heap_->raw_unchecked_null_value(); +@@ -1433,8 +1434,8 @@ void MarkCompactCollector::MarkLiveObjects() { + SymbolTableCleaner v(heap()); + symbol_table->IterateElements(&v); + symbol_table->ElementsRemoved(v.PointersRemoved()); +- heap()->external_string_table_.Iterate(&v); +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.Iterate(&v); ++ heap()->external_resource_table_.CleanUp(); + + // Process the weak references. + MarkCompactWeakObjectRetainer mark_compact_object_retainer; +@@ -1948,11 +1949,11 @@ static void UpdatePointerToNewGen(HeapObject** p) { + } + + +-static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + Address old_addr = HeapObject::cast(*p)->address(); + Address new_addr = Memory::Address_at(old_addr); +- return String::cast(HeapObject::FromAddress(new_addr)); ++ return HeapObject::FromAddress(new_addr); + } + + +@@ -2083,8 +2084,8 @@ static void SweepNewSpace(Heap* heap, NewSpace* space) { + updating_visitor.VisitPointer(heap->global_contexts_list_address()); + + // Update pointers from external string table. +- heap->UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ heap->UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + // All pointers were updated. Update auxiliary allocation info. + heap->IncrementYoungSurvivorsCounter(survivors_size); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 6aaca2f..231b835 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1392,13 +1392,13 @@ int JSObject::GetInternalFieldCount() { + // Make sure to adjust for the number of in-object properties. These + // properties do contribute to the size, but are not internal fields. + return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - +- map()->inobject_properties(); ++ map()->inobject_properties() - map()->has_external_resource()?1:0; + } + + + int JSObject::GetInternalFieldOffset(int index) { + ASSERT(index < GetInternalFieldCount() && index >= 0); +- return GetHeaderSize() + (kPointerSize * index); ++ return GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + } + + +@@ -1407,7 +1407,7 @@ Object* JSObject::GetInternalField(int index) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); ++ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0))); + } + + +@@ -1416,12 +1416,29 @@ void JSObject::SetInternalField(int index, Object* value) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- int offset = GetHeaderSize() + (kPointerSize * index); ++ int offset = GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); + } + + ++void JSObject::SetExternalResourceObject(Object *value) { ++ ASSERT(map()->has_external_resource()); ++ int offset = GetHeaderSize(); ++ WRITE_FIELD(this, offset, value); ++ WRITE_BARRIER(this, offset); ++} ++ ++ ++Object *JSObject::GetExternalResourceObject() { ++ if (map()->has_external_resource()) { ++ return READ_FIELD(this, GetHeaderSize()); ++ } else { ++ return GetHeap()->undefined_value(); ++ } ++} ++ ++ + // Access fast-case object properties at index. The use of these routines + // is needed to correctly distinguish between properties stored in-object and + // properties stored in the properties array. +@@ -2521,6 +2538,20 @@ bool Map::is_shared() { + } + + ++void Map::set_has_external_resource(bool value) { ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kHasExternalResource)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kHasExternalResource)); ++ } ++} ++ ++bool Map::has_external_resource() ++{ ++ return ((1 << kHasExternalResource) & bit_field3()) != 0; ++} ++ ++ + void Map::set_named_interceptor_is_fallback(bool value) + { + if (value) { +@@ -3017,6 +3048,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) + ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) + ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) ++ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, ++ kHasExternalResourceOffset) + + ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) + ACCESSORS(SignatureInfo, args, Object, kArgsOffset) +diff --git a/src/objects.h b/src/objects.h +index a209cd0..1bdb5c7 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1636,6 +1636,9 @@ class JSObject: public HeapObject { + inline Object* GetInternalField(int index); + inline void SetInternalField(int index, Object* value); + ++ inline void SetExternalResourceObject(Object *); ++ inline Object *GetExternalResourceObject(); ++ + // Lookup a property. If found, the result is valid and has + // detailed information. + void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); +@@ -3715,6 +3718,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Tells whether the instance has the space for an external resource ++ // object ++ inline void set_has_external_resource(bool value); ++ inline bool has_external_resource(); ++ + + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); +@@ -3912,6 +3921,7 @@ class Map: public HeapObject { + + // Bit positions for bit field 3 + static const int kNamedInterceptorIsFallback = 0; ++ static const int kHasExternalResource = 1; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6426,6 +6436,7 @@ class ObjectTemplateInfo: public TemplateInfo { + public: + DECL_ACCESSORS(constructor, Object) + DECL_ACCESSORS(internal_field_count, Object) ++ DECL_ACCESSORS(has_external_resource, Object) + + static inline ObjectTemplateInfo* cast(Object* obj); + +@@ -6442,7 +6453,8 @@ class ObjectTemplateInfo: public TemplateInfo { + static const int kConstructorOffset = TemplateInfo::kHeaderSize; + static const int kInternalFieldCountOffset = + kConstructorOffset + kPointerSize; +- static const int kSize = kInternalFieldCountOffset + kPointerSize; ++ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; ++ static const int kSize = kHasExternalResourceOffset + kPointerSize; + }; + + +-- +1.7.2.3 + diff --git a/src/v8/0005-Introduce-a-QML-compilation-mode.patch b/src/v8/0005-Introduce-a-QML-compilation-mode.patch new file mode 100644 index 00000000000..b464e612663 --- /dev/null +++ b/src/v8/0005-Introduce-a-QML-compilation-mode.patch @@ -0,0 +1,1777 @@ +From fd7d475e298e5b63cd6383c78cc900635c82aa38 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 23 May 2011 18:26:19 +1000 +Subject: [PATCH 05/13] Introduce a QML compilation mode + +In QML mode, there is a second global object - known as the QML +global object. During property resolution, if a property is not +present on the JS global object, it is resolve on the QML global +object. + +This global object behavior is only enabled if a script is being +compiled in QML mode. The object to use as the QML global object +is passed as a parameter to the Script::Run() method. Any function +closures etc. created during the run will retain a reference to this +object, so different objects can be passed in different script +runs. +--- + include/v8.h | 18 ++++++++-- + src/api.cc | 52 ++++++++++++++++++++++++----- + src/arm/code-stubs-arm.cc | 4 ++ + src/arm/full-codegen-arm.cc | 26 ++++++++------ + src/arm/lithium-arm.cc | 2 +- + src/arm/lithium-arm.h | 6 +++- + src/arm/lithium-codegen-arm.cc | 7 ++-- + src/arm/macro-assembler-arm.h | 5 +++ + src/ast-inl.h | 5 +++ + src/ast.h | 1 + + src/code-stubs.h | 2 +- + src/compiler.cc | 15 +++++++- + src/compiler.h | 22 ++++++++++-- + src/contexts.cc | 23 +++++++++++++ + src/contexts.h | 4 ++ + src/execution.cc | 28 +++++++++++++-- + src/execution.h | 6 +++ + src/full-codegen.cc | 3 +- + src/full-codegen.h | 1 + + src/heap.cc | 2 + + src/hydrogen-instructions.h | 10 ++++- + src/hydrogen.cc | 2 + + src/ia32/code-stubs-ia32.cc | 7 ++++ + src/ia32/full-codegen-ia32.cc | 26 ++++++++------ + src/ia32/lithium-codegen-ia32.cc | 7 ++-- + src/ia32/lithium-ia32.cc | 2 +- + src/ia32/lithium-ia32.h | 6 +++- + src/ia32/macro-assembler-ia32.h | 5 +++ + src/objects-inl.h | 12 +++++++ + src/objects.h | 5 +++ + src/parser.cc | 27 +++++++++++++-- + src/parser.h | 4 ++- + src/prettyprinter.cc | 3 ++ + src/runtime.cc | 68 ++++++++++++++++++++++++------------- + src/runtime.h | 8 ++-- + src/scopes.cc | 10 +++++ + src/scopes.h | 7 ++++ + src/variables.cc | 3 +- + src/variables.h | 5 +++ + src/x64/code-stubs-x64.cc | 4 ++ + src/x64/full-codegen-x64.cc | 26 ++++++++------ + src/x64/lithium-codegen-x64.cc | 7 ++-- + src/x64/lithium-x64.cc | 2 +- + src/x64/lithium-x64.h | 6 +++ + src/x64/macro-assembler-x64.h | 5 +++ + 45 files changed, 391 insertions(+), 108 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 7f06ae7..a858eae 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -577,6 +577,10 @@ class ScriptOrigin { + */ + class V8EXPORT Script { + public: ++ enum CompileFlags { ++ Default = 0x00, ++ QmlMode = 0x01 ++ }; + + /** + * Compiles the specified script (context-independent). +@@ -596,7 +600,8 @@ class V8EXPORT Script { + static Local