From ce8a1ef6f1a2868c6e4c19a56e94ca623b6b9889 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 1 Jul 2011 16:30:34 +1000 Subject: [PATCH] Update V8 Change-Id: I2736cb8fffaace5cbb9e91d12a75bdedf3f80627 Reviewed-on: http://codereview.qt.nokia.com/988 Reviewed-by: Aaron Kennedy --- src/3rdparty/v8 | 2 +- ...shing-and-comparison-methods-to-v8-String.patch | 187 +++++++- src/v8/0002-Add-a-bit-field-3-to-Map.patch | 14 +- ...back-mode-for-named-property-interceptors.patch | 26 +- ...0004-Generalize-external-object-resources.patch | 48 +- src/v8/0005-Introduce-a-QML-compilation-mode.patch | 484 ++++++++++++++++---- ...6-Allow-access-to-the-calling-script-data.patch | 12 +- src/v8/0007-Fix-warnings.patch | 10 +- .../0008-Add-custom-object-compare-callback.patch | 489 ++++++++++++++++++++ 9 files changed, 1109 insertions(+), 163 deletions(-) create mode 100644 src/v8/0008-Add-custom-object-compare-callback.patch diff --git a/src/3rdparty/v8 b/src/3rdparty/v8 index f7c8bc0..eb2dadf 160000 --- a/src/3rdparty/v8 +++ b/src/3rdparty/v8 @@ -1 +1 @@ -Subproject commit f7c8bc0d210ba97fad3261c5581f48221610f503 +Subproject commit eb2dadf516823ec342e6d75a3a78b2af7b1dea85 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 index 57a0ae8..e18e5bc 100644 --- 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 @@ -1,22 +1,25 @@ -From b828611412fae2c423b6e02d3fb266400492c4c0 Mon Sep 17 00:00:00 2001 +From 9a956953836844f1342ac012f4c2408405224fcd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 23 May 2011 15:47:20 +1000 -Subject: [PATCH 1/7] Add hashing and comparison methods to v8::String +Subject: [PATCH 1/8] 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 | 20 ++++++++++++++++++ - src/api.cc | 28 ++++++++++++++++++++++++++ - src/objects.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - src/objects.h | 3 ++ - 4 files changed, 111 insertions(+), 0 deletions(-) + include/v8.h | 43 +++++++++++++++++++++++++++++ + src/api.cc | 39 +++++++++++++++++++++++++++ + 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, 177 insertions(+), 3 deletions(-) diff --git a/include/v8.h b/include/v8.h -index d15d024..bd48503 100644 +index d15d024..626f34c 100644 --- a/include/v8.h +++ b/include/v8.h -@@ -994,6 +994,24 @@ class String : public Primitive { +@@ -994,6 +994,47 @@ class String : public Primitive { V8EXPORT int Utf8Length() const; /** @@ -24,6 +27,29 @@ index d15d024..bd48503 100644 + */ + 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. @@ -41,7 +67,7 @@ index d15d024..bd48503 100644 * 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 +1041,8 @@ class String : public Primitive { +@@ -1023,6 +1064,8 @@ class String : public Primitive { HINT_MANY_WRITES_EXPECTED = 1 }; @@ -51,10 +77,10 @@ index d15d024..bd48503 100644 int start = 0, int length = -1, diff --git a/src/api.cc b/src/api.cc -index a2373cd..f509673 100644 +index a2373cd..0d860bd 100644 --- a/src/api.cc +++ b/src/api.cc -@@ -3284,6 +3284,34 @@ int String::Utf8Length() const { +@@ -3284,6 +3284,45 @@ int String::Utf8Length() const { return str->Utf8Length(); } @@ -64,6 +90,17 @@ index a2373cd..f509673 100644 + 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; +} @@ -89,8 +126,68 @@ index a2373cd..f509673 100644 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..5bd7f95 100644 +index df61956..877da3d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate, @@ -160,8 +257,34 @@ index df61956..5bd7f95 100644 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(next_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..f4c27d2 100644 +index e966b3d..6e26f57 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5359,6 +5359,9 @@ class String: public HeapObject { @@ -174,6 +297,42 @@ index e966b3d..f4c27d2 100644 // 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 index 86820d7..98cc017 100644 --- a/src/v8/0002-Add-a-bit-field-3-to-Map.patch +++ b/src/v8/0002-Add-a-bit-field-3-to-Map.patch @@ -1,7 +1,7 @@ -From f2d11bae75512a1173da7b9f9edfaeeb1a1e73ce Mon Sep 17 00:00:00 2001 +From 4ce6693b28f0a699acd91c0ae88ae917cc273e9a Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 23 May 2011 15:55:26 +1000 -Subject: [PATCH 2/7] Add a bit field 3 to Map +Subject: [PATCH 2/8] Add a bit field 3 to Map Bit field 3 will be used to add QML specific map flags. --- @@ -12,7 +12,7 @@ Bit field 3 will be used to add QML specific map flags. 4 files changed, 22 insertions(+), 1 deletions(-) diff --git a/src/heap.cc b/src/heap.cc -index 2b6c11f..4a58bf6 100644 +index 930c97b..900f462 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -1573,6 +1573,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, @@ -32,10 +32,10 @@ index 2b6c11f..4a58bf6 100644 // 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 65aec5d..bbe05f6 100644 +index c82080d..cce3edd 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h -@@ -2429,6 +2429,16 @@ void Map::set_bit_field2(byte value) { +@@ -2430,6 +2430,16 @@ void Map::set_bit_field2(byte value) { } @@ -53,7 +53,7 @@ index 65aec5d..bbe05f6 100644 if (value) { set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); diff --git a/src/objects.cc b/src/objects.cc -index 5bd7f95..92ab958 100644 +index 877da3d..2409ea3 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3614,6 +3614,7 @@ MaybeObject* Map::CopyDropDescriptors() { @@ -73,7 +73,7 @@ index 5bd7f95..92ab958 100644 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); diff --git a/src/objects.h b/src/objects.h -index f4c27d2..a61733e 100644 +index 6e26f57..07e1089 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3597,6 +3597,10 @@ class Map: public HeapObject { 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 index cef7012..6af02cf 100644 --- 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 @@ -1,7 +1,7 @@ -From 7ccd4af88f3323405ef834acabee15e1e6748474 Mon Sep 17 00:00:00 2001 +From 5adbbff4a7f09a02d5c2d9b4e15dde89080e2405 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 23 May 2011 16:21:02 +1000 -Subject: [PATCH 3/7] Add a "fallback" mode for named property interceptors +Subject: [PATCH 3/8] 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 @@ -24,10 +24,10 @@ declarations. 9 files changed, 99 insertions(+), 18 deletions(-) diff --git a/include/v8.h b/include/v8.h -index bd48503..94da79c 100644 +index 626f34c..06085ec 100644 --- a/include/v8.h +++ b/include/v8.h -@@ -2145,6 +2145,7 @@ class V8EXPORT FunctionTemplate : public Template { +@@ -2168,6 +2168,7 @@ class V8EXPORT FunctionTemplate : public Template { NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, @@ -35,7 +35,7 @@ index bd48503..94da79c 100644 Handle data); void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, IndexedPropertySetter setter, -@@ -2229,6 +2230,13 @@ class V8EXPORT ObjectTemplate : public Template { +@@ -2252,6 +2253,13 @@ class V8EXPORT ObjectTemplate : public Template { NamedPropertyEnumerator enumerator = 0, Handle data = Handle()); @@ -50,7 +50,7 @@ index bd48503..94da79c 100644 * Sets an indexed property handler on the object template. * diff --git a/src/api.cc b/src/api.cc -index f509673..2ac4395 100644 +index 0d860bd..c20b062 100644 --- a/src/api.cc +++ b/src/api.cc @@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( @@ -151,10 +151,10 @@ index 3839f37..4b42506 100644 Handle SetProperty(Handle object, Handle key, diff --git a/src/objects-inl.h b/src/objects-inl.h -index bbe05f6..0c09e84 100644 +index cce3edd..6aaca2f 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h -@@ -2520,6 +2520,21 @@ bool Map::is_shared() { +@@ -2521,6 +2521,21 @@ bool Map::is_shared() { } @@ -176,7 +176,7 @@ index bbe05f6..0c09e84 100644 JSFunction* Map::unchecked_constructor() { return reinterpret_cast(READ_FIELD(this, kConstructorOffset)); } -@@ -2969,6 +2984,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) +@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) ACCESSORS(InterceptorInfo, data, Object, kDataOffset) @@ -185,7 +185,7 @@ index bbe05f6..0c09e84 100644 ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) diff --git a/src/objects.cc b/src/objects.cc -index 92ab958..08d130e 100644 +index 2409ea3..f1e4c8c 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( @@ -246,7 +246,7 @@ index 92ab958..08d130e 100644 } result->NotFound(); diff --git a/src/objects.h b/src/objects.h -index a61733e..3fdc69f 100644 +index 07e1089..a209cd0 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1405,7 +1405,8 @@ class JSObject: public HeapObject { @@ -291,7 +291,7 @@ index a61733e..3fdc69f 100644 // Layout of the default cache. It holds alternating name and code objects. static const int kCodeCacheEntrySize = 2; -@@ -6268,6 +6276,7 @@ class InterceptorInfo: public Struct { +@@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct { DECL_ACCESSORS(deleter, Object) DECL_ACCESSORS(enumerator, Object) DECL_ACCESSORS(data, Object) @@ -299,7 +299,7 @@ index a61733e..3fdc69f 100644 static inline InterceptorInfo* cast(Object* obj); -@@ -6287,7 +6296,8 @@ class InterceptorInfo: public Struct { +@@ -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; diff --git a/src/v8/0004-Generalize-external-object-resources.patch b/src/v8/0004-Generalize-external-object-resources.patch index 9c30763..3d5686f 100644 --- a/src/v8/0004-Generalize-external-object-resources.patch +++ b/src/v8/0004-Generalize-external-object-resources.patch @@ -1,7 +1,7 @@ -From a9108d655fcd8ffa45a32257160cc10eaf0256ee Mon Sep 17 00:00:00 2001 +From 8f640251aeac30f08ddb7bc4c0fe6ba6ff7eabdd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 23 May 2011 16:55:35 +1000 -Subject: [PATCH 4/7] Generalize external object resources +Subject: [PATCH 4/8] Generalize external object resources V8 was already able to manage and finalize an external string resource. This change generalizes that mechanism to handle a @@ -31,10 +31,10 @@ object space. 11 files changed, 280 insertions(+), 115 deletions(-) diff --git a/include/v8.h b/include/v8.h -index 94da79c..b377c53 100644 +index 06085ec..9740251 100644 --- a/include/v8.h +++ b/include/v8.h -@@ -1606,6 +1606,25 @@ class Object : public Value { +@@ -1629,6 +1629,25 @@ class Object : public Value { /** Sets a native pointer in an internal field. */ V8EXPORT void SetPointerInInternalField(int index, void* value); @@ -60,7 +60,7 @@ index 94da79c..b377c53 100644 // Testers for local properties. V8EXPORT bool HasRealNamedProperty(Handle key); V8EXPORT bool HasRealIndexedProperty(uint32_t index); -@@ -2307,6 +2326,12 @@ class V8EXPORT ObjectTemplate : public Template { +@@ -2330,6 +2349,12 @@ class V8EXPORT ObjectTemplate : public Template { */ void SetInternalFieldCount(int value); @@ -74,7 +74,7 @@ index 94da79c..b377c53 100644 ObjectTemplate(); static Local New(Handle constructor); diff --git a/src/api.cc b/src/api.cc -index 2ac4395..3137d6c 100644 +index c20b062..d81ece8 100644 --- a/src/api.cc +++ b/src/api.cc @@ -1294,6 +1294,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) { @@ -112,7 +112,7 @@ index 2ac4395..3137d6c 100644 // --- S c r i p t D a t a --- -@@ -3637,6 +3665,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { +@@ -3648,6 +3676,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { } @@ -147,7 +147,7 @@ index 2ac4395..3137d6c 100644 // --- E n v i r o n m e n t --- -@@ -4129,7 +4185,7 @@ Local v8::String::NewExternal( +@@ -4140,7 +4196,7 @@ Local v8::String::NewExternal( LOG_API(isolate, "String::NewExternal"); ENTER_V8(isolate); i::Handle result = NewExternalStringHandle(isolate, resource); @@ -156,7 +156,7 @@ index 2ac4395..3137d6c 100644 return Utils::ToLocal(result); } -@@ -4147,7 +4203,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { +@@ -4158,7 +4214,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { } bool result = obj->MakeExternal(resource); if (result && !obj->IsSymbol()) { @@ -165,7 +165,7 @@ index 2ac4395..3137d6c 100644 } return result; } -@@ -4160,7 +4216,7 @@ Local v8::String::NewExternal( +@@ -4171,7 +4227,7 @@ Local v8::String::NewExternal( LOG_API(isolate, "String::NewExternal"); ENTER_V8(isolate); i::Handle result = NewExternalAsciiStringHandle(isolate, resource); @@ -174,7 +174,7 @@ index 2ac4395..3137d6c 100644 return Utils::ToLocal(result); } -@@ -4179,7 +4235,7 @@ bool v8::String::MakeExternal( +@@ -4190,7 +4246,7 @@ bool v8::String::MakeExternal( } bool result = obj->MakeExternal(resource); if (result && !obj->IsSymbol()) { @@ -244,10 +244,10 @@ index dcdc645..d530a75 100644 if (obj->undetectable()) { map->set_is_undetectable(); diff --git a/src/heap-inl.h b/src/heap-inl.h -index 99737ed..84f8b39 100644 +index f4fce7b..58e7adf 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h -@@ -203,21 +203,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) { +@@ -205,21 +205,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) { } @@ -298,7 +298,7 @@ index 99737ed..84f8b39 100644 } -@@ -554,53 +569,63 @@ inline bool Heap::allow_allocation(bool new_state) { +@@ -556,53 +571,63 @@ inline bool Heap::allow_allocation(bool new_state) { #endif @@ -387,7 +387,7 @@ index 99737ed..84f8b39 100644 } diff --git a/src/heap.cc b/src/heap.cc -index 4a58bf6..46df787 100644 +index 900f462..bf2940e 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -155,7 +155,7 @@ Heap::Heap() @@ -476,7 +476,7 @@ index 4a58bf6..46df787 100644 } -@@ -4465,7 +4465,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { +@@ -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. @@ -485,7 +485,7 @@ index 4a58bf6..46df787 100644 } v->Synchronize("external_string_table"); } -@@ -4967,7 +4967,7 @@ void Heap::TearDown() { +@@ -4970,7 +4970,7 @@ void Heap::TearDown() { isolate_->global_handles()->TearDown(); @@ -494,7 +494,7 @@ index 4a58bf6..46df787 100644 new_space_.TearDown(); -@@ -5832,31 +5832,31 @@ void TranscendentalCache::Clear() { +@@ -5835,31 +5835,31 @@ void TranscendentalCache::Clear() { } @@ -747,7 +747,7 @@ index 68a5062..1b1e361 100644 // 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 0c09e84..a205f02 100644 +index 6aaca2f..231b835 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1392,13 +1392,13 @@ int JSObject::GetInternalFieldCount() { @@ -806,7 +806,7 @@ index 0c09e84..a205f02 100644 // 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. -@@ -2520,6 +2537,20 @@ bool Map::is_shared() { +@@ -2521,6 +2538,20 @@ bool Map::is_shared() { } @@ -827,7 +827,7 @@ index 0c09e84..a205f02 100644 void Map::set_named_interceptor_is_fallback(bool value) { if (value) { -@@ -3016,6 +3047,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) +@@ -3017,6 +3048,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, kInternalFieldCountOffset) @@ -837,7 +837,7 @@ index 0c09e84..a205f02 100644 ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) ACCESSORS(SignatureInfo, args, Object, kArgsOffset) diff --git a/src/objects.h b/src/objects.h -index 3fdc69f..439ad1e 100644 +index a209cd0..1bdb5c7 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1636,6 +1636,9 @@ class JSObject: public HeapObject { @@ -871,7 +871,7 @@ index 3fdc69f..439ad1e 100644 // Layout of the default cache. It holds alternating name and code objects. static const int kCodeCacheEntrySize = 2; -@@ -6418,6 +6428,7 @@ class ObjectTemplateInfo: public TemplateInfo { +@@ -6426,6 +6436,7 @@ class ObjectTemplateInfo: public TemplateInfo { public: DECL_ACCESSORS(constructor, Object) DECL_ACCESSORS(internal_field_count, Object) @@ -879,7 +879,7 @@ index 3fdc69f..439ad1e 100644 static inline ObjectTemplateInfo* cast(Object* obj); -@@ -6434,7 +6445,8 @@ class ObjectTemplateInfo: public TemplateInfo { +@@ -6442,7 +6453,8 @@ class ObjectTemplateInfo: public TemplateInfo { static const int kConstructorOffset = TemplateInfo::kHeaderSize; static const int kInternalFieldCountOffset = kConstructorOffset + kPointerSize; diff --git a/src/v8/0005-Introduce-a-QML-compilation-mode.patch b/src/v8/0005-Introduce-a-QML-compilation-mode.patch index 5b85166..930e2b9 100644 --- a/src/v8/0005-Introduce-a-QML-compilation-mode.patch +++ b/src/v8/0005-Introduce-a-QML-compilation-mode.patch @@ -1,7 +1,7 @@ -From 2762e881e1990169c3d9d9f02d5db56d79de79ba Mon Sep 17 00:00:00 2001 +From de8b6a719219677dc8e34248de7836369bf1034d Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 23 May 2011 18:26:19 +1000 -Subject: [PATCH 5/7] Introduce a QML compilation mode +Subject: [PATCH 5/8] 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 @@ -15,43 +15,55 @@ 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 | 21 +++++++----- - src/arm/macro-assembler-arm.h | 5 +++ - src/ast-inl.h | 5 +++ - src/ast.h | 1 + - src/compiler.cc | 15 +++++++- - src/compiler.h | 24 +++++++++++--- - 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/ia32/code-stubs-ia32.cc | 7 ++++ - src/ia32/full-codegen-ia32.cc | 21 +++++++----- - 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 | 16 +++++++++ - 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 | 21 +++++++----- - src/x64/macro-assembler-x64.h | 5 +++ - 33 files changed, 347 insertions(+), 86 deletions(-) + 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 b377c53..a67feb2 100644 +index 9740251..d04b73e 100644 --- a/include/v8.h +++ b/include/v8.h @@ -577,6 +577,10 @@ class ScriptOrigin { @@ -113,7 +125,7 @@ index b377c53..a67feb2 100644 /** * Returns the script id value. -@@ -3302,6 +3311,7 @@ class V8EXPORT Context { +@@ -3325,6 +3334,7 @@ class V8EXPORT Context { * JavaScript frames an empty handle is returned. */ static Local GetCalling(); @@ -122,7 +134,7 @@ index b377c53..a67feb2 100644 /** * Sets the security token for the context. To access an object in diff --git a/src/api.cc b/src/api.cc -index 3137d6c..61ed79e 100644 +index d81ece8..0635f34 100644 --- a/src/api.cc +++ b/src/api.cc @@ -1372,7 +1372,8 @@ ScriptData* ScriptData::New(const char* data, int length) { @@ -207,7 +219,7 @@ index 3137d6c..61ed79e 100644 EXCEPTION_BAILOUT_CHECK(isolate, Local()); raw_result = *result; } -@@ -3928,6 +3938,30 @@ v8::Local Context::GetCalling() { +@@ -3939,6 +3949,30 @@ v8::Local Context::GetCalling() { } @@ -254,10 +266,26 @@ index 8c147f9..a2626bf 100644 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc -index 871b453..f132de6 100644 +index 871b453..a69f10d 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc -@@ -1247,9 +1247,9 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( +@@ -154,12 +154,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment cmnt(masm_, "[ Allocate local context"); + // Argument to NewContext is the function, which is in r1. + __ push(r1); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -1247,9 +1248,9 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( __ bind(&fast); } @@ -269,7 +297,7 @@ index 871b453..f132de6 100644 ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; Handle ic = isolate()->builtins()->LoadIC_Initialize(); -@@ -1268,10 +1268,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { +@@ -1268,10 +1269,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in r2 and the global // object (receiver) in r0. @@ -282,7 +310,7 @@ index 871b453..f132de6 100644 context()->Plug(r0); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { -@@ -1893,11 +1893,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, +@@ -1893,11 +1894,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // assignment. Right-hand-side value is passed in r0, variable name in // r2, and the global object in r1. __ mov(r2, Operand(var->name())); @@ -296,7 +324,7 @@ index 871b453..f132de6 100644 } else if (op == Token::INIT_CONST) { // Like var declarations, const declarations are hoisted to function -@@ -2184,10 +2184,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, +@@ -2184,10 +2185,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, // Push the strict mode flag. __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); __ push(r1); @@ -311,7 +339,7 @@ index 871b453..f132de6 100644 } -@@ -2263,9 +2266,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { +@@ -2263,9 +2267,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { context()->DropAndPlug(1, r0); } else if (var != NULL && !var->is_this() && var->is_global()) { // Push global object as receiver for the call IC. @@ -323,6 +351,71 @@ index 871b453..f132de6 100644 } else if (var != NULL && var->AsSlot() != NULL && var->AsSlot()->type() == Slot::LOOKUP) { // Call to a lookup slot (dynamically introduced variable). +diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc +index 3f1d15b..8406a96 100644 +--- a/src/arm/lithium-arm.cc ++++ b/src/arm/lithium-arm.cc +@@ -1195,7 +1195,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { + + LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { + LOperand* context = UseRegisterAtStart(instr->value()); +- return DefineAsRegister(new LGlobalObject(context)); ++ return DefineAsRegister(new LGlobalObject(context, instr->qml_global())); + } + + +diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h +index 6da7c86..10b901f 100644 +--- a/src/arm/lithium-arm.h ++++ b/src/arm/lithium-arm.h +@@ -1378,13 +1378,17 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { + + class LGlobalObject: public LTemplateInstruction<1, 1, 0> { + public: +- explicit LGlobalObject(LOperand* context) { ++ explicit LGlobalObject(LOperand* context, bool qml_global) { + inputs_[0] = context; ++ qml_global_ = qml_global; + } + + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + + LOperand* context() { return InputAt(0); } ++ bool qml_global() { return qml_global_; } ++ private: ++ bool qml_global_; + }; + + +diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc +index 4912449..db114ea 100644 +--- a/src/arm/lithium-codegen-arm.cc ++++ b/src/arm/lithium-codegen-arm.cc +@@ -166,12 +166,13 @@ bool LCodeGen::GeneratePrologue() { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment(";;; Allocate local context"); + // Argument to NewContext is the function, which is in r1. + __ push(r1); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -2664,7 +2665,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) { + void LCodeGen::DoGlobalObject(LGlobalObject* instr) { + Register context = ToRegister(instr->context()); + Register result = ToRegister(instr->result()); +- __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX)); ++ __ ldr(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)); + } + + diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index ab5efb0..d40cdbc 100644 --- a/src/arm/macro-assembler-arm.h @@ -367,6 +460,19 @@ index 65a25a9..f790dc0 100644 int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } +diff --git a/src/code-stubs.h b/src/code-stubs.h +index 56ef072..37e5383 100644 +--- a/src/code-stubs.h ++++ b/src/code-stubs.h +@@ -303,7 +303,7 @@ class FastNewContextStub : public CodeStub { + static const int kMaximumSlots = 64; + + explicit FastNewContextStub(int slots) : slots_(slots) { +- ASSERT(slots_ > 0 && slots <= kMaximumSlots); ++ ASSERT(slots_ >= 0 && slots <= kMaximumSlots); + } + + void Generate(MacroAssembler* masm); diff --git a/src/compiler.cc b/src/compiler.cc index 86d5de3..d2191b9 100755 --- a/src/compiler.cc @@ -429,7 +535,7 @@ index 86d5de3..d2191b9 100755 diff --git a/src/compiler.h b/src/compiler.h -index e75e869..ca4b62d 100644 +index e75e869..17cd369 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -54,6 +54,7 @@ class CompilationInfo BASE_EMBEDDED { @@ -450,16 +556,14 @@ index e75e869..ca4b62d 100644 void MarkAsAllowingNativesSyntax() { flags_ |= IsNativesSyntaxAllowed::encode(true); } -@@ -141,7 +145,8 @@ class CompilationInfo BASE_EMBEDDED { +@@ -141,6 +145,7 @@ class CompilationInfo BASE_EMBEDDED { // Determine whether or not we can adaptively optimize. bool AllowOptimize() { -- return V8::UseCrankshaft() && !closure_.is_null(); + // XXX - fix qml mode optimizations -+ return V8::UseCrankshaft() && !closure_.is_null() && !is_qml_mode(); + return V8::UseCrankshaft() && !closure_.is_null(); } - private: @@ -163,8 +168,13 @@ class CompilationInfo BASE_EMBEDDED { void Initialize(Mode mode) { @@ -697,10 +801,10 @@ index d6ed1b9..e3241aa 100644 Scope* scope() { return info_->scope(); } diff --git a/src/heap.cc b/src/heap.cc -index 46df787..6e02262 100644 +index bf2940e..da958c2 100644 --- a/src/heap.cc +++ b/src/heap.cc -@@ -3792,6 +3792,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { +@@ -3795,6 +3795,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { context->set_previous(NULL); context->set_extension(NULL); context->set_global(function->context()->global()); @@ -708,7 +812,7 @@ index 46df787..6e02262 100644 ASSERT(!context->IsGlobalContext()); ASSERT(context->is_function_context()); ASSERT(result->IsContext()); -@@ -3814,6 +3815,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous, +@@ -3817,6 +3818,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous, context->set_previous(previous); context->set_extension(extension); context->set_global(previous->global()); @@ -716,6 +820,63 @@ index 46df787..6e02262 100644 ASSERT(!context->IsGlobalContext()); ASSERT(!context->is_function_context()); ASSERT(result->IsContext()); +diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h +index a623775..52455bc 100644 +--- a/src/hydrogen-instructions.h ++++ b/src/hydrogen-instructions.h +@@ -1148,7 +1148,7 @@ class HOuterContext: public HUnaryOperation { + + class HGlobalObject: public HUnaryOperation { + public: +- explicit HGlobalObject(HValue* context) : HUnaryOperation(context) { ++ explicit HGlobalObject(HValue* context) : HUnaryOperation(context), qml_global_(false) { + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + } +@@ -1159,8 +1159,14 @@ class HGlobalObject: public HUnaryOperation { + return Representation::Tagged(); + } + ++ bool qml_global() { return qml_global_; } ++ void set_qml_global(bool v) { qml_global_ = v; } ++ + protected: + virtual bool DataEquals(HValue* other) { return true; } ++ ++ private: ++ bool qml_global_; + }; + + +@@ -1177,7 +1183,7 @@ class HGlobalReceiver: public HUnaryOperation { + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } +- ++ + protected: + virtual bool DataEquals(HValue* other) { return true; } + }; +diff --git a/src/hydrogen.cc b/src/hydrogen.cc +index 73ea97d..d17e304 100644 +--- a/src/hydrogen.cc ++++ b/src/hydrogen.cc +@@ -2918,6 +2918,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { + HContext* context = new(zone()) HContext; + AddInstruction(context); + HGlobalObject* global_object = new(zone()) HGlobalObject(context); ++ if (variable->is_qml_global()) global_object->set_qml_global(true); + AddInstruction(global_object); + HLoadGlobalGeneric* instr = + new(zone()) HLoadGlobalGeneric(context, +@@ -3307,6 +3308,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, + HContext* context = new(zone()) HContext; + AddInstruction(context); + HGlobalObject* global_object = new(zone()) HGlobalObject(context); ++ if (var->is_qml_global()) global_object->set_qml_global(true); + AddInstruction(global_object); + HStoreGlobalGeneric* instr = + new(zone()) HStoreGlobalGeneric(context, diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 5d32095..afa599e 100644 --- a/src/ia32/code-stubs-ia32.cc @@ -735,10 +896,26 @@ index 5d32095..afa599e 100644 __ mov(ebx, factory->undefined_value()); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc -index 5d153a8..28b78ba 100644 +index 5d153a8..0ddcde2 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc -@@ -1107,10 +1107,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( +@@ -142,12 +142,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment cmnt(masm_, "[ Allocate local context"); + // Argument to NewContext is the function, which is still in edi. + __ push(edi); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -1107,10 +1108,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // load IC call. @@ -751,7 +928,7 @@ index 5d153a8..28b78ba 100644 ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; EmitCallIC(ic, mode); -@@ -1214,10 +1214,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { +@@ -1214,10 +1215,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in ecx and the global // object on the stack. @@ -764,7 +941,7 @@ index 5d153a8..28b78ba 100644 context()->Plug(eax); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { -@@ -1837,11 +1837,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, +@@ -1837,11 +1838,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // assignment. Right-hand-side value is passed in eax, variable name in // ecx, and the global object on the stack. __ mov(ecx, var->name()); @@ -778,7 +955,7 @@ index 5d153a8..28b78ba 100644 } else if (op == Token::INIT_CONST) { // Like var declarations, const declarations are hoisted to function -@@ -2113,9 +2113,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, +@@ -2113,9 +2114,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, // Push the strict mode flag. __ push(Immediate(Smi::FromInt(strict_mode_flag()))); @@ -792,7 +969,7 @@ index 5d153a8..28b78ba 100644 } -@@ -2188,8 +2191,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { +@@ -2188,8 +2192,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { context()->DropAndPlug(1, eax); } else if (var != NULL && !var->is_this() && var->is_global()) { // Push global object as receiver for the call IC. @@ -803,6 +980,71 @@ index 5d153a8..28b78ba 100644 } else if (var != NULL && var->AsSlot() != NULL && var->AsSlot()->type() == Slot::LOOKUP) { // Call to a lookup slot (dynamically introduced variable). +diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc +index 0f96f78..c1da075 100644 +--- a/src/ia32/lithium-codegen-ia32.cc ++++ b/src/ia32/lithium-codegen-ia32.cc +@@ -159,12 +159,13 @@ bool LCodeGen::GeneratePrologue() { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment(";;; Allocate local context"); + // Argument to NewContext is the function, which is still in edi. + __ push(edi); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -2525,7 +2526,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) { + void LCodeGen::DoGlobalObject(LGlobalObject* instr) { + Register context = ToRegister(instr->context()); + Register result = ToRegister(instr->result()); +- __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX))); ++ __ mov(result, Operand(context, Context::SlotOffset(instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX))); + } + + +diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc +index 9ccd189..8e98b73 100644 +--- a/src/ia32/lithium-ia32.cc ++++ b/src/ia32/lithium-ia32.cc +@@ -1205,7 +1205,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { + + LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { + LOperand* context = UseRegisterAtStart(instr->value()); +- return DefineAsRegister(new LGlobalObject(context)); ++ return DefineAsRegister(new LGlobalObject(context, instr->qml_global())); + } + + +diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h +index 9ace8f8..95ed001 100644 +--- a/src/ia32/lithium-ia32.h ++++ b/src/ia32/lithium-ia32.h +@@ -1416,13 +1416,17 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { + + class LGlobalObject: public LTemplateInstruction<1, 1, 0> { + public: +- explicit LGlobalObject(LOperand* context) { ++ explicit LGlobalObject(LOperand* context, bool qml_global) { + inputs_[0] = context; ++ qml_global_ = qml_global; + } + + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + + LOperand* context() { return InputAt(0); } ++ bool qml_global() { return qml_global_; } ++ private: ++ bool qml_global_; + }; + + diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index b986264..f8479ae 100644 --- a/src/ia32/macro-assembler-ia32.h @@ -820,10 +1062,10 @@ index b986264..f8479ae 100644 Operand ApiParameterOperand(int index); diff --git a/src/objects-inl.h b/src/objects-inl.h -index a205f02..8c0c2d0 100644 +index 231b835..1c7f83e 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h -@@ -3241,6 +3241,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) { +@@ -3242,6 +3242,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) { } @@ -843,7 +1085,7 @@ index a205f02..8c0c2d0 100644 ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset) diff --git a/src/objects.h b/src/objects.h -index 439ad1e..918ab61 100644 +index 1bdb5c7..edbc47a 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4331,6 +4331,10 @@ class SharedFunctionInfo: public HeapObject { @@ -1245,7 +1487,7 @@ index bf1ba68..5e97173 100644 F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ \ diff --git a/src/scopes.cc b/src/scopes.cc -index 8df93c5..e34e762 100644 +index 8df93c5..734a217 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -198,6 +198,7 @@ void Scope::SetDefaults(Type type, @@ -1256,15 +1498,7 @@ index 8df93c5..e34e762 100644 outer_scope_calls_eval_ = false; inner_scope_calls_eval_ = false; outer_scope_is_eval_scope_ = false; -@@ -516,6 +517,7 @@ bool Scope::HasTrivialContext() const { - if (scope->is_eval_scope()) return false; - if (scope->scope_inside_with_) return false; - if (scope->num_heap_slots_ > 0) return false; -+ if (scope->qml_mode_ && is_global_scope() && inner_scopes_.length()) return false; - } - return true; - } -@@ -796,6 +798,10 @@ void Scope::ResolveVariable(Scope* global_scope, +@@ -796,6 +797,10 @@ void Scope::ResolveVariable(Scope* global_scope, ASSERT(global_scope != NULL); var = global_scope->DeclareGlobal(proxy->name()); @@ -1275,7 +1509,7 @@ index 8df93c5..e34e762 100644 } else if (scope_inside_with_) { // If we are inside a with statement we give up and look up // the variable at runtime. -@@ -816,6 +822,8 @@ void Scope::ResolveVariable(Scope* global_scope, +@@ -816,6 +821,8 @@ void Scope::ResolveVariable(Scope* global_scope, // variables. if (context->GlobalIfNotShadowedByEval(proxy->name())) { var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); @@ -1284,7 +1518,7 @@ index 8df93c5..e34e762 100644 } else { var = NonLocal(proxy->name(), Variable::DYNAMIC); -@@ -827,6 +835,9 @@ void Scope::ResolveVariable(Scope* global_scope, +@@ -827,6 +834,9 @@ void Scope::ResolveVariable(Scope* global_scope, // variable is global unless it is shadowed by eval-introduced // variables. var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); @@ -1294,18 +1528,6 @@ index 8df93c5..e34e762 100644 } } } -@@ -1112,6 +1123,11 @@ void Scope::AllocateVariablesRecursively() { - must_have_local_context = is_function_scope(); - } - -+ if (qml_mode_ && is_global_scope() && inner_scopes_.length()) { -+ must_have_local_context = true; -+ num_heap_slots_++; // This is a hack to force a context to be allocated to save the QML global -+ } -+ - // If we didn't allocate any locals in the local context, then we only - // need the minimal number of slots if we must have a local context. - if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && diff --git a/src/scopes.h b/src/scopes.h index a0e56a4..6dd3f65 100644 --- a/src/scopes.h @@ -1391,10 +1613,26 @@ index c365385..d923494 100644 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc -index 97168cd..342fe9b 100644 +index 97168cd..c45cdb6 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc -@@ -1119,10 +1119,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( +@@ -141,12 +141,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment cmnt(masm_, "[ Allocate local context"); + // Argument to NewContext is the function, which is still in rdi. + __ push(rdi); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -1119,10 +1120,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( // All extension objects were empty and it is safe to use a global // load IC call. @@ -1407,7 +1645,7 @@ index 97168cd..342fe9b 100644 ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; EmitCallIC(ic, mode); -@@ -1227,9 +1227,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { +@@ -1227,9 +1228,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { // Use inline caching. Variable name is passed in rcx and the global // object on the stack. __ Move(rcx, var->name()); @@ -1419,7 +1657,7 @@ index 97168cd..342fe9b 100644 context()->Plug(rax); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { -@@ -1806,11 +1806,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, +@@ -1806,11 +1807,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // assignment. Right-hand-side value is passed in rax, variable name in // rcx, and the global object on the stack. __ Move(rcx, var->name()); @@ -1433,7 +1671,7 @@ index 97168cd..342fe9b 100644 } else if (op == Token::INIT_CONST) { // Like var declarations, const declarations are hoisted to function -@@ -2085,9 +2085,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, +@@ -2085,9 +2086,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, // Push the strict mode flag. __ Push(Smi::FromInt(strict_mode_flag())); @@ -1447,7 +1685,7 @@ index 97168cd..342fe9b 100644 } -@@ -2160,8 +2163,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { +@@ -2160,8 +2164,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { } else if (var != NULL && !var->is_this() && var->is_global()) { // Call to a global variable. // Push global object as receiver for the call IC lookup. @@ -1458,6 +1696,66 @@ index 97168cd..342fe9b 100644 } else if (var != NULL && var->AsSlot() != NULL && var->AsSlot()->type() == Slot::LOOKUP) { // Call to a lookup slot (dynamically introduced variable). +diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc +index 202e7a2..45acbdf 100644 +--- a/src/x64/lithium-codegen-x64.cc ++++ b/src/x64/lithium-codegen-x64.cc +@@ -174,12 +174,13 @@ bool LCodeGen::GeneratePrologue() { + + // Possibly allocate a local context. + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; +- if (heap_slots > 0) { ++ if (heap_slots > 0 || ++ (scope()->is_qml_mode() && scope()->is_global_scope())) { + Comment(";;; Allocate local context"); + // Argument to NewContext is the function, which is still in rdi. + __ push(rdi); + if (heap_slots <= FastNewContextStub::kMaximumSlots) { +- FastNewContextStub stub(heap_slots); ++ FastNewContextStub stub((heap_slots < 0)?0:heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kNewContext, 1); +@@ -2540,7 +2541,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) { + + void LCodeGen::DoGlobalObject(LGlobalObject* instr) { + Register result = ToRegister(instr->result()); +- __ movq(result, GlobalObjectOperand()); ++ __ movq(result, instr->qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + } + + +diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc +index 07ca3a5..00feeac 100644 +--- a/src/x64/lithium-x64.cc ++++ b/src/x64/lithium-x64.cc +@@ -1194,7 +1194,7 @@ LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { + + + LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { +- return DefineAsRegister(new LGlobalObject); ++ return DefineAsRegister(new LGlobalObject(instr->qml_global())); + } + + +diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h +index 15bb894..16f754c 100644 +--- a/src/x64/lithium-x64.h ++++ b/src/x64/lithium-x64.h +@@ -1365,7 +1365,13 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { + + class LGlobalObject: public LTemplateInstruction<1, 0, 0> { + public: ++ explicit LGlobalObject(bool qml_global) : qml_global_(qml_global) {} ++ + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") ++ ++ bool qml_global() { return qml_global_; } ++ private: ++ bool qml_global_; + }; + + diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 4c17720..aa284ed 100644 --- a/src/x64/macro-assembler-x64.h diff --git a/src/v8/0006-Allow-access-to-the-calling-script-data.patch b/src/v8/0006-Allow-access-to-the-calling-script-data.patch index cc4fbab..214fe82 100644 --- a/src/v8/0006-Allow-access-to-the-calling-script-data.patch +++ b/src/v8/0006-Allow-access-to-the-calling-script-data.patch @@ -1,7 +1,7 @@ -From bbf7e31aa48416f43efbff97eb84b89954fa6607 Mon Sep 17 00:00:00 2001 +From 55ac15fff18ba2d0469c92c533e7ceb1c343fcd9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 25 May 2011 10:36:13 +1000 -Subject: [PATCH 6/7] Allow access to the calling script data +Subject: [PATCH 6/8] Allow access to the calling script data --- include/v8.h | 1 + @@ -9,10 +9,10 @@ Subject: [PATCH 6/7] Allow access to the calling script data 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/include/v8.h b/include/v8.h -index a67feb2..6577a30 100644 +index d04b73e..5f9e725 100644 --- a/include/v8.h +++ b/include/v8.h -@@ -3312,6 +3312,7 @@ class V8EXPORT Context { +@@ -3335,6 +3335,7 @@ class V8EXPORT Context { */ static Local GetCalling(); static Local GetCallingQmlGlobal(); @@ -21,10 +21,10 @@ index a67feb2..6577a30 100644 /** * Sets the security token for the context. To access an object in diff --git a/src/api.cc b/src/api.cc -index 61ed79e..f2fb371 100644 +index 0635f34..ba487e8 100644 --- a/src/api.cc +++ b/src/api.cc -@@ -3961,6 +3961,18 @@ v8::Local Context::GetCallingQmlGlobal() { +@@ -3972,6 +3972,18 @@ v8::Local Context::GetCallingQmlGlobal() { } } diff --git a/src/v8/0007-Fix-warnings.patch b/src/v8/0007-Fix-warnings.patch index 5292ae0..1b7da91 100644 --- a/src/v8/0007-Fix-warnings.patch +++ b/src/v8/0007-Fix-warnings.patch @@ -1,17 +1,17 @@ -From f7c8bc0d210ba97fad3261c5581f48221610f503 Mon Sep 17 00:00:00 2001 +From d37bb342f33c384e912ec7d86dfda8f384253ddd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 27 May 2011 13:04:15 +1000 -Subject: [PATCH 7/7] Fix warnings +Subject: [PATCH 7/8] Fix warnings --- include/v8.h | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/v8.h b/include/v8.h -index 6577a30..3e1f520 100644 +index 5f9e725..255b90b 100644 --- a/include/v8.h +++ b/include/v8.h -@@ -2391,7 +2391,7 @@ class V8EXPORT Extension { // NOLINT +@@ -2414,7 +2414,7 @@ class V8EXPORT Extension { // NOLINT const char** deps = 0); virtual ~Extension() { } virtual v8::Handle @@ -20,7 +20,7 @@ index 6577a30..3e1f520 100644 return v8::Handle(); } -@@ -3697,13 +3697,13 @@ class Internals { +@@ -3720,13 +3720,13 @@ class Internals { return *reinterpret_cast(addr); } diff --git a/src/v8/0008-Add-custom-object-compare-callback.patch b/src/v8/0008-Add-custom-object-compare-callback.patch new file mode 100644 index 0000000..ecc6eaa --- /dev/null +++ b/src/v8/0008-Add-custom-object-compare-callback.patch @@ -0,0 +1,489 @@ +From eb2dadf516823ec342e6d75a3a78b2af7b1dea85 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +Date: Mon, 27 Jun 2011 14:57:28 +1000 +Subject: [PATCH 8/8] 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 255b90b..52a5839 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2364,6 +2364,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 New(Handle constructor); +@@ -2564,6 +2570,10 @@ typedef void (*FailedAccessCheckCallback)(Local target, + AccessType type, + Local 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 lhs, ++ Local 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 + + /** +@@ -2814,6 +2824,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 ba487e8..930f338 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 --- + +@@ -4628,6 +4638,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* objects, + size_t length, + RetainedObjectInfo* info) { +diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc +index a2626bf..749c9be 100644 +--- a/src/arm/code-stubs-arm.cc ++++ b/src/arm/code-stubs-arm.cc +@@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) { + // NOTICE! This code is only reached after a smi-fast-case check, so + // it is certain that at least one operand isn't a smi. + ++ { ++ Label not_user_equal, user_equal; ++ __ and_(r2, r1, Operand(r0)); ++ __ tst(r2, Operand(kSmiTagMask)); ++ __ b(eq, ¬_user_equal); ++ ++ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE); ++ __ b(ne, ¬_user_equal); ++ ++ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE); ++ __ b(ne, ¬_user_equal); ++ ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &user_equal); ++ ++ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset)); ++ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(ne, ¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ Push(r0, r1); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ + // Handle the case where the objects are identical. Either returns the answer + // or goes to slow. Only falls through if the objects were not identical. + EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); +@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + __ tst(r2, Operand(kSmiTagMask)); + __ b(eq, &miss); + +- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); ++ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE); + __ b(ne, &miss); +- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &miss); ++ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE); + __ b(ne, &miss); ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &miss); + + ASSERT(GetCondition() == eq); + __ sub(r0, r0, Operand(r1)); +diff --git a/src/factory.cc b/src/factory.cc +index d530a75..6f8c7de 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -998,6 +998,7 @@ Handle Factory::CreateApiFunction( + + int internal_field_count = 0; + bool has_external_resource = false; ++ bool use_user_object_comparison = false; + + if (!obj->instance_template()->IsUndefined()) { + Handle instance_template = +@@ -1007,6 +1008,8 @@ Handle 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 Factory::CreateApiFunction( + map->set_has_external_resource(true); + } + ++ // Mark as using user object comparison if needed ++ if (use_user_object_comparison) { ++ map->set_use_user_object_comparison(true); ++ } ++ + // Mark as undetectable if needed. + if (obj->undetectable()) { + map->set_is_undetectable(); +diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc +index afa599e..0964ab9 100644 +--- a/src/ia32/code-stubs-ia32.cc ++++ b/src/ia32/code-stubs-ia32.cc +@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) { + __ Assert(not_zero, "Unexpected smi operands."); + } + ++ { ++ NearLabel not_user_equal, user_equal; ++ __ test(eax, Immediate(kSmiTagMask)); ++ __ j(zero, ¬_user_equal); ++ __ test(edx, Immediate(kSmiTagMask)); ++ __ j(zero, ¬_user_equal); ++ ++ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ test_b(FieldOperand(ebx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &user_equal); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &user_equal); ++ ++ __ jmp(¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ pop(ebx); // Return address. ++ __ push(eax); ++ __ push(edx); ++ __ push(ebx); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ ++ + // NOTICE! This code is only reached after a smi-fast-case check, so + // it is certain that at least one operand isn't a smi. + +@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + + __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); + __ j(not_equal, &miss, not_taken); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &miss); + __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); + __ j(not_equal, &miss, not_taken); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &miss); + + ASSERT(GetCondition() == equal); + __ sub(eax, Operand(edx)); +diff --git a/src/isolate.h b/src/isolate.h +index 35ffcb4..8130397 100644 +--- a/src/isolate.h ++++ b/src/isolate.h +@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED { + // Call back function to report unsafe JS accesses. + v8::FailedAccessCheckCallback failed_access_check_callback_; + ++ // Call back function for user object comparisons ++ v8::UserObjectComparisonCallback user_object_comparison_callback_; ++ + private: + void InitializeInternal(); + +@@ -699,6 +702,11 @@ class Isolate { + void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback); + void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); + ++ void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback); ++ inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() { ++ return thread_local_top()->user_object_comparison_callback_; ++ } ++ + // Exception throwing support. The caller should use the result + // of Throw() as its return value. + Failure* Throw(Object* exception, MessageLocation* location = NULL); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 1c7f83e..1765441 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2552,6 +2552,19 @@ bool Map::has_external_resource() + } + + ++void Map::set_use_user_object_comparison(bool value) { ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison)); ++ } ++} ++ ++bool Map::use_user_object_comparison() { ++ return ((1 << kUseUserObjectComparison) & bit_field3()) != 0; ++} ++ ++ + void Map::set_named_interceptor_is_fallback(bool value) + { + if (value) { +@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) + ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, + kHasExternalResourceOffset) ++ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object, ++ kUseUserObjectComparisonOffset) + + ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) + ACCESSORS(SignatureInfo, args, Object, kArgsOffset) +diff --git a/src/objects.h b/src/objects.h +index edbc47a..e75e9f1 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -3724,6 +3724,11 @@ class Map: public HeapObject { + inline void set_has_external_resource(bool value); + inline bool has_external_resource(); + ++ ++ // Tells whether the user object comparison callback should be used for ++ // comparisons involving this object ++ inline void set_use_user_object_comparison(bool value); ++ inline bool use_user_object_comparison(); + + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); +@@ -3922,6 +3927,7 @@ class Map: public HeapObject { + // Bit positions for bit field 3 + static const int kNamedInterceptorIsFallback = 0; + static const int kHasExternalResource = 1; ++ static const int kUseUserObjectComparison = 2; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo { + DECL_ACCESSORS(constructor, Object) + DECL_ACCESSORS(internal_field_count, Object) + DECL_ACCESSORS(has_external_resource, Object) ++ DECL_ACCESSORS(use_user_object_comparison, Object) + + static inline ObjectTemplateInfo* cast(Object* obj); + +@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo { + static const int kInternalFieldCountOffset = + kConstructorOffset + kPointerSize; + static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; +- static const int kSize = kHasExternalResourceOffset + kPointerSize; ++ static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize; ++ static const int kSize = kUseUserObjectComparisonOffset + kPointerSize; + }; + + +diff --git a/src/runtime.cc b/src/runtime.cc +index 827d954..d552ddb 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { + } + + ++RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) { ++ NoHandleAllocation ha; ++ ASSERT(args.length() == 2); ++ ++ CONVERT_CHECKED(JSObject, lhs, args[1]); ++ CONVERT_CHECKED(JSObject, rhs, args[0]); ++ ++ bool result; ++ ++ v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback(); ++ if (callback) { ++ HandleScope scope(isolate); ++ Handle lhs_handle(lhs); ++ Handle rhs_handle(rhs); ++ result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle)); ++ } else { ++ result = (lhs == rhs); ++ } ++ ++ return Smi::FromInt(result?0:1); ++} ++ ++ + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { + NoHandleAllocation ha; + ASSERT(args.length() == 3); +diff --git a/src/runtime.h b/src/runtime.h +index 5e97173..0d754f9 100644 +--- a/src/runtime.h ++++ b/src/runtime.h +@@ -146,6 +146,7 @@ namespace internal { + /* Comparisons */ \ + F(NumberEquals, 2, 1) \ + F(StringEquals, 2, 1) \ ++ F(UserObjectEquals, 2, 1) \ + \ + F(NumberCompare, 3, 1) \ + F(SmiLexicographicCompare, 2, 1) \ +diff --git a/src/top.cc b/src/top.cc +index e078ee9..c345383 100644 +--- a/src/top.cc ++++ b/src/top.cc +@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() { + thread_id_ = ThreadId::Invalid(); + external_caught_exception_ = false; + failed_access_check_callback_ = NULL; ++ user_object_comparison_callback_ = NULL; + save_context_ = NULL; + catcher_ = NULL; + } +@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback( + thread_local_top()->failed_access_check_callback_ = callback; + } + ++void Isolate::SetUserObjectComparisonCallback( ++ v8::UserObjectComparisonCallback callback) { ++ thread_local_top()->user_object_comparison_callback_ = callback; ++} + + void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { + if (!thread_local_top()->failed_access_check_callback_) return; +diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc +index d923494..10b9b56 100644 +--- a/src/x64/code-stubs-x64.cc ++++ b/src/x64/code-stubs-x64.cc +@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) { + __ bind(&ok); + } + ++ { ++ NearLabel not_user_equal, user_equal; ++ __ JumpIfSmi(rax, ¬_user_equal); ++ __ JumpIfSmi(rdx, ¬_user_equal); ++ ++ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ testb(FieldOperand(rbx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &user_equal); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &user_equal); ++ ++ __ jmp(¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ pop(rbx); // Return address. ++ __ push(rax); ++ __ push(rdx); ++ __ push(rbx); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ + // The compare stub returns a positive, negative, or zero 64-bit integer + // value in rax, corresponding to result of comparing the two inputs. + // NOTICE! This code is only reached after a smi-fast-case check, so +@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + + __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); + __ j(not_equal, &miss, not_taken); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &miss); + __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); + __ j(not_equal, &miss, not_taken); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &miss); + + ASSERT(GetCondition() == equal); + __ subq(rax, rdx); +-- +1.7.2.3 + -- 1.7.2.5