Update V8
authorAaron Kennedy <aaron.kennedy@nokia.com>
Fri, 1 Jul 2011 06:30:34 +0000 (16:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 1 Jul 2011 06:32:25 +0000 (08:32 +0200)
Change-Id: I2736cb8fffaace5cbb9e91d12a75bdedf3f80627
Reviewed-on: http://codereview.qt.nokia.com/988
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
src/3rdparty/v8
src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch
src/v8/0002-Add-a-bit-field-3-to-Map.patch
src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch
src/v8/0004-Generalize-external-object-resources.patch
src/v8/0005-Introduce-a-QML-compilation-mode.patch
src/v8/0006-Allow-access-to-the-calling-script-data.patch
src/v8/0007-Fix-warnings.patch
src/v8/0008-Add-custom-object-compare-callback.patch [new file with mode: 0644]

index f7c8bc0..eb2dadf 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f7c8bc0d210ba97fad3261c5581f48221610f503
+Subproject commit eb2dadf516823ec342e6d75a3a78b2af7b1dea85
index 57a0ae8..e18e5bc 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<i::String> str = Utils::OpenHandle(this);
++  if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData();
++  CompleteHashData result;
++  result.length = str->length();
++  result.hash = str->Hash();
++  if (str->IsSeqString())
++      result.symbol_id = i::SeqString::cast(*str)->symbol_id();
++  return result;
++}
++
 +uint32_t String::ComputeHash(uint16_t *string, int length) {
 +  return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift;
 +}
@@ -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<const char> str,
+   String* answer = String::cast(result);
+   answer->set_length(str.length());
+   answer->set_hash_field(hash_field);
++  SeqString::cast(answer)->set_symbol_id(0);
+   ASSERT_EQ(size, answer->Size());
+@@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
+   String* answer = String::cast(result);
+   answer->set_length(str.length());
+   answer->set_hash_field(hash_field);
++  SeqString::cast(answer)->set_symbol_id(0);
+   ASSERT_EQ(size, answer->Size());
+diff --git a/src/heap.cc b/src/heap.cc
+index 2b6c11f..930c97b 100644
+--- a/src/heap.cc
++++ b/src/heap.cc
+@@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
+   String* answer = String::cast(result);
+   answer->set_length(chars);
+   answer->set_hash_field(hash_field);
++  SeqString::cast(result)->set_symbol_id(0);
+   ASSERT_EQ(size, answer->Size());
+@@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
+   HeapObject::cast(result)->set_map(ascii_string_map());
+   String::cast(result)->set_length(length);
+   String::cast(result)->set_hash_field(String::kEmptyHashField);
++  SeqString::cast(result)->set_symbol_id(0);
+   ASSERT_EQ(size, HeapObject::cast(result)->Size());
+   return result;
+ }
+@@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length,
+   HeapObject::cast(result)->set_map(string_map());
+   String::cast(result)->set_length(length);
+   String::cast(result)->set_hash_field(String::kEmptyHashField);
++  SeqString::cast(result)->set_symbol_id(0);
+   ASSERT_EQ(size, HeapObject::cast(result)->Size());
+   return result;
+ }
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 65aec5d..c82080d 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset)
+ SMI_ACCESSORS(String, length, kLengthOffset)
++SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset)
+ uint32_t String::hash_field() {
 diff --git a/src/objects.cc b/src/objects.cc
-index df61956..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<char> {
+   MaybeObject* AsObject() {
+     if (hash_field_ == 0) Hash();
+-    return HEAP->AllocateAsciiSymbol(string_, hash_field_);
++    MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_);
++    if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) {
++        while (true) {
++            Atomic32 my_symbol_id = next_symbol_id;
++            if (my_symbol_id > Smi::kMaxValue)
++                break;
++            if (my_symbol_id ==NoBarrier_CompareAndSwap(&next_symbol_id, my_symbol_id, my_symbol_id + 1)) {
++                SeqString::cast(result->ToObjectUnchecked())->set_symbol_id(next_symbol_id++);
++                break;
++            }
++        }
++    }
++    return result;
+   }
++
++  static Atomic32 next_symbol_id;
+ };
++Atomic32 AsciiSymbolKey::next_symbol_id = 1;
+ class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
 diff --git a/src/objects.h b/src/objects.h
-index e966b3d..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
 
index 86820d7..98cc017 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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 {
index cef7012..6af02cf 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<Value> 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<Value> data = Handle<Value>());
  
@@ -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<Object> SetProperty(Handle<Object> object,
                             Handle<Object> 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<JSFunction*>(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;
index 9c30763..3d5686f 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<String> 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<ObjectTemplate> New(Handle<FunctionTemplate> 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<String> v8::String::NewExternal(
+@@ -4140,7 +4196,7 @@ Local<String> v8::String::NewExternal(
    LOG_API(isolate, "String::NewExternal");
    ENTER_V8(isolate);
    i::Handle<i::String> 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<String> v8::String::NewExternal(
+@@ -4171,7 +4227,7 @@ Local<String> v8::String::NewExternal(
    LOG_API(isolate, "String::NewExternal");
    ENTER_V8(isolate);
    i::Handle<i::String> 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;
index 5b85166..930e2b9 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<Context> 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<Value>());
      raw_result = *result;
    }
-@@ -3928,6 +3938,30 @@ v8::Local<v8::Context> Context::GetCalling() {
+@@ -3939,6 +3949,30 @@ v8::Local<v8::Context> 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<Code> 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
index cc4fbab..214fe82 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<Context> GetCalling();
    static Local<Object> 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<v8::Object> Context::GetCallingQmlGlobal() {
+@@ -3972,6 +3972,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
    }
  }
  
index 5292ae0..1b7da91 100644 (file)
@@ -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 <aaron.kennedy@nokia.com>
 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<v8::FunctionTemplate>
@@ -20,7 +20,7 @@ index 6577a30..3e1f520 100644
      return v8::Handle<v8::FunctionTemplate>();
    }
  
-@@ -3697,13 +3697,13 @@ class Internals {
+@@ -3720,13 +3720,13 @@ class Internals {
      return *reinterpret_cast<T*>(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 (file)
index 0000000..ecc6eaa
--- /dev/null
@@ -0,0 +1,489 @@
+From eb2dadf516823ec342e6d75a3a78b2af7b1dea85 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 27 Jun 2011 14:57:28 +1000
+Subject: [PATCH 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<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
+@@ -2564,6 +2570,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
+                                           AccessType type,
+                                           Local<Value> data);
++// --- U s e r O b j e c t C o m p a r i s o n C a l l b a c k ---
++typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs, 
++                                             Local<Object> rhs);
++
+ // --- G a r b a g e C o l l e c t i o n  C a l l b a c k s
+ /**
+@@ -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<Value>* objects,
+                         size_t length,
+                         RetainedObjectInfo* info) {
+diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
+index a2626bf..749c9be 100644
+--- a/src/arm/code-stubs-arm.cc
++++ b/src/arm/code-stubs-arm.cc
+@@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) {
+   // NOTICE! This code is only reached after a smi-fast-case check, so
+   // it is certain that at least one operand isn't a smi.
++  {
++      Label not_user_equal, user_equal;
++      __ and_(r2, r1, Operand(r0));
++      __ tst(r2, Operand(kSmiTagMask));
++      __ b(eq, &not_user_equal);
++
++      __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
++      __ b(ne, &not_user_equal);
++
++      __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
++      __ b(ne, &not_user_equal);
++
++      __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++      __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++      __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++      __ b(eq, &user_equal);
++
++      __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset));
++      __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
++      __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
++      __ b(ne, &not_user_equal);
++
++      __ bind(&user_equal);
++
++      __ Push(r0, r1);
++      __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++
++      __ bind(&not_user_equal);
++  }
++
+   // Handle the case where the objects are identical.  Either returns the answer
+   // or goes to slow.  Only falls through if the objects were not identical.
+   EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
+@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+   __ tst(r2, Operand(kSmiTagMask));
+   __ b(eq, &miss);
+-  __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
++  __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
+   __ b(ne, &miss);
+-  __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
++  __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++  __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++  __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++  __ b(eq, &miss);
++  __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
+   __ b(ne, &miss);
++  __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
++  __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
++  __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
++  __ b(eq, &miss);
+   ASSERT(GetCondition() == eq);
+   __ sub(r0, r0, Operand(r1));
+diff --git a/src/factory.cc b/src/factory.cc
+index d530a75..6f8c7de 100644
+--- a/src/factory.cc
++++ b/src/factory.cc
+@@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
+   int internal_field_count = 0;
+   bool has_external_resource = false;
++  bool use_user_object_comparison = false;
+   if (!obj->instance_template()->IsUndefined()) {
+     Handle<ObjectTemplateInfo> instance_template =
+@@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
+         Smi::cast(instance_template->internal_field_count())->value();
+     has_external_resource =
+         !instance_template->has_external_resource()->IsUndefined();
++    use_user_object_comparison =
++        !instance_template->use_user_object_comparison()->IsUndefined();
+   }
+   int instance_size = kPointerSize * internal_field_count;
+@@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
+     map->set_has_external_resource(true);
+   }
++  // Mark as using user object comparison if needed
++  if (use_user_object_comparison) {
++    map->set_use_user_object_comparison(true);
++  }
++
+   // Mark as undetectable if needed.
+   if (obj->undetectable()) {
+     map->set_is_undetectable();
+diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
+index afa599e..0964ab9 100644
+--- a/src/ia32/code-stubs-ia32.cc
++++ b/src/ia32/code-stubs-ia32.cc
+@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
+     __ Assert(not_zero, "Unexpected smi operands.");
+   }
++  {
++    NearLabel not_user_equal, user_equal;
++    __ test(eax, Immediate(kSmiTagMask));
++    __ j(zero, &not_user_equal);
++    __ test(edx, Immediate(kSmiTagMask));
++    __ j(zero, &not_user_equal);
++
++    __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
++    __ j(not_equal, &not_user_equal);
++
++    __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
++    __ j(not_equal, &not_user_equal);
++
++    __ test_b(FieldOperand(ebx, Map::kBitField3Offset),
++              1 << Map::kUseUserObjectComparison);
++    __ j(not_zero, &user_equal);
++    __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++              1 << Map::kUseUserObjectComparison);
++    __ j(not_zero, &user_equal);
++
++    __ jmp(&not_user_equal);
++
++    __ bind(&user_equal);
++   
++    __ pop(ebx); // Return address.
++    __ push(eax);
++    __ push(edx);
++    __ push(ebx);
++    __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++   
++    __ bind(&not_user_equal);
++  }
++
++
+   // NOTICE! This code is only reached after a smi-fast-case check, so
+   // it is certain that at least one operand isn't a smi.
+@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+   __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
+   __ j(not_equal, &miss, not_taken);
++  __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++            1 << Map::kUseUserObjectComparison);
++  __ j(not_zero, &miss);
+   __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+   __ j(not_equal, &miss, not_taken);
++  __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
++            1 << Map::kUseUserObjectComparison);
++  __ j(not_zero, &miss);
+   ASSERT(GetCondition() == equal);
+   __ sub(eax, Operand(edx));
+diff --git a/src/isolate.h b/src/isolate.h
+index 35ffcb4..8130397 100644
+--- a/src/isolate.h
++++ b/src/isolate.h
+@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED {
+   // Call back function to report unsafe JS accesses.
+   v8::FailedAccessCheckCallback failed_access_check_callback_;
++  // Call back function for user object comparisons
++  v8::UserObjectComparisonCallback user_object_comparison_callback_;
++
+  private:
+   void InitializeInternal();
+@@ -699,6 +702,11 @@ class Isolate {
+   void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
+   void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
++  void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback);
++  inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() { 
++      return thread_local_top()->user_object_comparison_callback_;
++  }
++
+   // Exception throwing support. The caller should use the result
+   // of Throw() as its return value.
+   Failure* Throw(Object* exception, MessageLocation* location = NULL);
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 1c7f83e..1765441 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -2552,6 +2552,19 @@ bool Map::has_external_resource()
+ }
+  
++void Map::set_use_user_object_comparison(bool value) {
++  if (value) {
++    set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison));
++  } else {
++    set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison));
++  }
++}
++
++bool Map::use_user_object_comparison() {
++    return ((1 << kUseUserObjectComparison) & bit_field3()) != 0;
++}
++
++
+ void Map::set_named_interceptor_is_fallback(bool value)
+ {
+   if (value) {
+@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
+           kInternalFieldCountOffset)
+ ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, 
+           kHasExternalResourceOffset)
++ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object, 
++          kUseUserObjectComparisonOffset)
+ ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
+ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
+diff --git a/src/objects.h b/src/objects.h
+index edbc47a..e75e9f1 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -3724,6 +3724,11 @@ class Map: public HeapObject {
+   inline void set_has_external_resource(bool value);
+   inline bool has_external_resource();
++
++  // Tells whether the user object comparison callback should be used for
++  // comparisons involving this object
++  inline void set_use_user_object_comparison(bool value);
++  inline bool use_user_object_comparison();
+  
+   // Whether the named interceptor is a fallback interceptor or not
+   inline void set_named_interceptor_is_fallback(bool value);
+@@ -3922,6 +3927,7 @@ class Map: public HeapObject {
+   // Bit positions for bit field 3
+   static const int kNamedInterceptorIsFallback = 0;
+   static const int kHasExternalResource = 1;
++  static const int kUseUserObjectComparison = 2;
+   // Layout of the default cache. It holds alternating name and code objects.
+   static const int kCodeCacheEntrySize = 2;
+@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo {
+   DECL_ACCESSORS(constructor, Object)
+   DECL_ACCESSORS(internal_field_count, Object)
+   DECL_ACCESSORS(has_external_resource, Object)
++  DECL_ACCESSORS(use_user_object_comparison, Object)
+   static inline ObjectTemplateInfo* cast(Object* obj);
+@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo {
+   static const int kInternalFieldCountOffset =
+       kConstructorOffset + kPointerSize;
+   static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
+-  static const int kSize = kHasExternalResourceOffset + kPointerSize;
++  static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize;
++  static const int kSize = kUseUserObjectComparisonOffset + kPointerSize;
+ };
+diff --git a/src/runtime.cc b/src/runtime.cc
+index 827d954..d552ddb 100644
+--- a/src/runtime.cc
++++ b/src/runtime.cc
+@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
+ }
++RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
++  NoHandleAllocation ha;
++  ASSERT(args.length() == 2);
++
++  CONVERT_CHECKED(JSObject, lhs, args[1]);
++  CONVERT_CHECKED(JSObject, rhs, args[0]);
++
++  bool result;
++
++  v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
++  if (callback) {
++      HandleScope scope(isolate);
++      Handle<JSObject> lhs_handle(lhs);
++      Handle<JSObject> rhs_handle(rhs);
++      result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
++  } else {
++      result = (lhs == rhs);
++  }
++
++  return Smi::FromInt(result?0:1);
++}
++
++
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
+   NoHandleAllocation ha;
+   ASSERT(args.length() == 3);
+diff --git a/src/runtime.h b/src/runtime.h
+index 5e97173..0d754f9 100644
+--- a/src/runtime.h
++++ b/src/runtime.h
+@@ -146,6 +146,7 @@ namespace internal {
+   /* Comparisons */ \
+   F(NumberEquals, 2, 1) \
+   F(StringEquals, 2, 1) \
++  F(UserObjectEquals, 2, 1) \
+   \
+   F(NumberCompare, 3, 1) \
+   F(SmiLexicographicCompare, 2, 1) \
+diff --git a/src/top.cc b/src/top.cc
+index e078ee9..c345383 100644
+--- a/src/top.cc
++++ b/src/top.cc
+@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() {
+   thread_id_ = ThreadId::Invalid();
+   external_caught_exception_ = false;
+   failed_access_check_callback_ = NULL;
++  user_object_comparison_callback_ = NULL;
+   save_context_ = NULL;
+   catcher_ = NULL;
+ }
+@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback(
+   thread_local_top()->failed_access_check_callback_ = callback;
+ }
++void Isolate::SetUserObjectComparisonCallback(
++    v8::UserObjectComparisonCallback callback) {
++  thread_local_top()->user_object_comparison_callback_ = callback;
++}
+ void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
+   if (!thread_local_top()->failed_access_check_callback_) return;
+diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
+index d923494..10b9b56 100644
+--- a/src/x64/code-stubs-x64.cc
++++ b/src/x64/code-stubs-x64.cc
+@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
+     __ bind(&ok);
+   }
++  {
++    NearLabel not_user_equal, user_equal;
++    __ JumpIfSmi(rax, &not_user_equal);
++    __ JumpIfSmi(rdx, &not_user_equal);
++
++    __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
++    __ j(not_equal, &not_user_equal);
++
++    __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
++    __ j(not_equal, &not_user_equal);
++
++    __ testb(FieldOperand(rbx, Map::kBitField3Offset),
++             Immediate(1 << Map::kUseUserObjectComparison));
++    __ j(not_zero, &user_equal);
++    __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++             Immediate(1 << Map::kUseUserObjectComparison));
++    __ j(not_zero, &user_equal);
++
++    __ jmp(&not_user_equal);
++
++    __ bind(&user_equal);
++   
++    __ pop(rbx); // Return address.
++    __ push(rax);
++    __ push(rdx);
++    __ push(rbx);
++    __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
++   
++    __ bind(&not_user_equal);
++  }
++
+   // The compare stub returns a positive, negative, or zero 64-bit integer
+   // value in rax, corresponding to result of comparing the two inputs.
+   // NOTICE! This code is only reached after a smi-fast-case check, so
+@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
+   __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
+   __ j(not_equal, &miss, not_taken);
++  __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++           Immediate(1 << Map::kUseUserObjectComparison));
++  __ j(not_zero, &miss);
+   __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+   __ j(not_equal, &miss, not_taken);
++  __ testb(FieldOperand(rcx, Map::kBitField3Offset),
++           Immediate(1 << Map::kUseUserObjectComparison));
++  __ j(not_zero, &miss);
+   ASSERT(GetCondition() == equal);
+   __ subq(rax, rdx);
+-- 
+1.7.2.3
+