diff options
Diffstat (limited to 'src')
20 files changed, 5279 insertions, 0 deletions
diff --git a/src/3rdparty/v8 b/src/3rdparty/v8 new file mode 160000 +Subproject dc2cad4f8fc88c52fcea09b8d0262d35cd32dc4 diff --git a/src/modules/qt_v8.pri b/src/modules/qt_v8.pri new file mode 100644 index 0000000000..89d6c263e8 --- /dev/null +++ b/src/modules/qt_v8.pri @@ -0,0 +1,16 @@ +QT.v8.VERSION = 5.0.0 +QT.v8.MAJOR_VERSION = 5 +QT.v8.MINOR_VERSION = 0 +QT.v8.PATCH_VERSION = 0 + +QT.v8.name = QtV8 +QT.v8.bins = $$QT_MODULE_BIN_BASE +QT.v8.includes = $$QT_MODULE_INCLUDE_BASE/QtV8 +QT.v8.private_includes = $$QT_MODULE_INCLUDE_BASE/QtV8/$$QT.v8.VERSION +QT.v8.sources = $$QT_MODULE_BASE/src/v8 +QT.v8.libs = $$QT_MODULE_LIB_BASE +QT.v8.plugins = $$QT_MODULE_PLUGIN_BASE +QT.v8.imports = $$QT_MODULE_IMPORT_BASE +QT.v8.depends = +QT.v8.DEFINES = +!contains(QT_CONFIG, static): QT.v8.DEFINES += V8_SHARED USING_V8_SHARED diff --git a/src/src.pro b/src/src.pro index 491973c635..caac6426f3 100644 --- a/src/src.pro +++ b/src/src.pro @@ -8,6 +8,7 @@ SRC_SUBDIRS += src_corelib src_network src_sql src_testlib src_xml src_uitools nacl: SRC_SUBDIRS -= src_network src_testlib !symbian:contains(QT_CONFIG, dbus):SRC_SUBDIRS += src_dbus !contains(QT_CONFIG, no-gui): SRC_SUBDIRS += src_gui +!contains(QT_CONFIG, no-v8): SRC_SUBDIRS += src_v8 !wince*:!symbian-abld:!symbian-sbsv2:include(tools/tools.pro) @@ -27,6 +28,8 @@ src_winmain.subdir = $$QT_SOURCE_TREE/src/winmain src_winmain.target = sub-winmain src_corelib.subdir = $$QT_SOURCE_TREE/src/corelib src_corelib.target = sub-corelib +src_v8.subdir = $$QT_SOURCE_TREE/src/v8 +src_v8.target = sub-v8 src_xml.subdir = $$QT_SOURCE_TREE/src/xml src_xml.target = sub-xml src_uitools.subdir = $$QT_SOURCE_TREE/src/uitools diff --git a/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch new file mode 100644 index 0000000000..54a35fda9f --- /dev/null +++ b/src/v8/0001-Add-hashing-and-comparison-methods-to-v8-String.patch @@ -0,0 +1,343 @@ +From e13ce09287a56c920d5ffdc5d4662d49f1838f16 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 15:47:20 +1000 +Subject: [PATCH 01/13] Add hashing and comparison methods to v8::String + +This allows us to more rapidly search for a v8::String inside +a hash of QStrings. +--- + include/v8.h | 44 ++++++++++++++++++++++++++++++ + src/api.cc | 43 +++++++++++++++++++++++++++++ + src/heap-inl.h | 2 + + src/heap.cc | 3 ++ + src/objects-inl.h | 1 + + src/objects.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + src/objects.h | 15 +++++++++- + 7 files changed, 182 insertions(+), 3 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index d15d024..bbd29e9 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -994,6 +994,48 @@ class String : public Primitive { + V8EXPORT int Utf8Length() const; + + /** ++ * Returns the hash of this string. ++ */ ++ V8EXPORT uint32_t Hash() const; ++ ++ struct CompleteHashData { ++ CompleteHashData() : length(0), hash(0), symbol_id(0) {} ++ int length; ++ uint32_t hash; ++ uint32_t symbol_id; ++ }; ++ ++ /** ++ * Returns the "complete" hash of the string. This is ++ * all the information about the string needed to implement ++ * a very efficient hash keyed on the string. ++ * ++ * The members of CompleteHashData are: ++ * length: The length of the string. Equivalent to Length() ++ * hash: The hash of the string. Equivalent to Hash() ++ * symbol_id: If the string is a sequential symbol, the symbol ++ * id, otherwise 0. If the symbol ids of two strings are ++ * the same (and non-zero) the two strings are identical. ++ * If the symbol ids are different the strings may still be ++ * identical, but an Equals() check must be performed. ++ */ ++ V8EXPORT CompleteHashData CompleteHash() const; ++ ++ /** ++ * Compute a hash value for the passed UTF16 string ++ * data. ++ */ ++ V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length); ++ V8EXPORT static uint32_t ComputeHash(char *string, int length); ++ ++ /** ++ * Returns true if this string is equal to the external ++ * string data provided. ++ */ ++ V8EXPORT bool Equals(uint16_t *string, int length); ++ V8EXPORT bool Equals(char *string, int length); ++ ++ /** + * Write the contents of the string to an external buffer. + * If no arguments are given, expects the buffer to be large + * enough to hold the entire string and NULL terminator. Copies +@@ -1023,6 +1065,8 @@ class String : public Primitive { + HINT_MANY_WRITES_EXPECTED = 1 + }; + ++ V8EXPORT uint16_t GetCharacter(int index); ++ + V8EXPORT int Write(uint16_t* buffer, + int start = 0, + int length = -1, +diff --git a/src/api.cc b/src/api.cc +index a2373cd..381935b 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3284,6 +3284,49 @@ int String::Utf8Length() const { + return str->Utf8Length(); + } + ++uint32_t String::Hash() const { ++ i::Handle<i::String> str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0; ++ return str->Hash(); ++} ++ ++String::CompleteHashData String::CompleteHash() const { ++ i::Handle<i::String> str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData(); ++ CompleteHashData result; ++ result.length = str->length(); ++ result.hash = str->Hash(); ++ if (str->IsSeqString()) ++ result.symbol_id = i::SeqString::cast(*str)->symbol_id(); ++ return result; ++} ++ ++uint32_t String::ComputeHash(uint16_t *string, int length) { ++ return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift; ++} ++ ++uint32_t String::ComputeHash(char *string, int length) { ++ return i::HashSequentialString<char>(string, length) >> i::String::kHashShift; ++} ++ ++uint16_t String::GetCharacter(int index) ++{ ++ i::Handle<i::String> str = Utils::OpenHandle(this); ++ return str->Get(index); ++} ++ ++bool String::Equals(uint16_t *string, int length) { ++ i::Handle<i::String> str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} ++ ++bool String::Equals(char *string, int length) ++{ ++ i::Handle<i::String> str = Utils::OpenHandle(this); ++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; ++ return str->SlowEqualsExternal(string, length); ++} + + int String::WriteUtf8(char* buffer, + int capacity, +diff --git a/src/heap-inl.h b/src/heap-inl.h +index 99737ed..f4fce7b 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -93,6 +93,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str, + String* answer = String::cast(result); + answer->set_length(str.length()); + answer->set_hash_field(hash_field); ++ SeqString::cast(answer)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +diff --git a/src/heap.cc b/src/heap.cc +index 2b6c11f..930c97b 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, + String* answer = String::cast(result); + answer->set_length(chars); + answer->set_hash_field(hash_field); ++ SeqString::cast(result)->set_symbol_id(0); + + ASSERT_EQ(size, answer->Size()); + +@@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { + HeapObject::cast(result)->set_map(ascii_string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +@@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length, + HeapObject::cast(result)->set_map(string_map()); + String::cast(result)->set_length(length); + String::cast(result)->set_hash_field(String::kEmptyHashField); ++ SeqString::cast(result)->set_symbol_id(0); + ASSERT_EQ(size, HeapObject::cast(result)->Size()); + return result; + } +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 65aec5d..c82080d 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset) + + + SMI_ACCESSORS(String, length, kLengthOffset) ++SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset) + + + uint32_t String::hash_field() { +diff --git a/src/objects.cc b/src/objects.cc +index df61956..dc4b260 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate, + } + } + ++bool String::SlowEqualsExternal(uc16 *string, int length) { ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (lhs->IsFlat()) { ++ if (lhs->IsAsciiRepresentation()) { ++ Vector<const char> vec1 = lhs->ToAsciiVector(); ++ VectorIterator<char> buf1(vec1); ++ VectorIterator<uc16> ib(string, length); ++ return CompareStringContents(&buf1, &ib); ++ } else { ++ Vector<const uc16> vec1 = lhs->ToUC16Vector(); ++ Vector<const uc16> vec2(string, length); ++ return CompareRawStringContents(vec1, vec2); ++ } ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator<uc16> ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} ++ ++bool String::SlowEqualsExternal(char *string, int length) ++{ ++ int len = this->length(); ++ if (len != length) return false; ++ if (len == 0) return true; ++ ++ // We know the strings are both non-empty. Compare the first chars ++ // before we try to flatten the strings. ++ if (this->Get(0) != string[0]) return false; ++ ++ String* lhs = this->TryFlattenGetString(); ++ ++ if (StringShape(lhs).IsSequentialAscii()) { ++ const char* str1 = SeqAsciiString::cast(lhs)->GetChars(); ++ return CompareRawStringContents(Vector<const char>(str1, len), ++ Vector<const char>(string, len)); ++ } ++ ++ if (lhs->IsFlat()) { ++ Vector<const uc16> vec1 = lhs->ToUC16Vector(); ++ VectorIterator<const uc16> buf1(vec1); ++ VectorIterator<char> buf2(string, length); ++ return CompareStringContents(&buf1, &buf2); ++ } else { ++ Isolate* isolate = GetIsolate(); ++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); ++ VectorIterator<char> ib(string, length); ++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); ++ } ++} + + bool String::SlowEquals(String* other) { + // Fast check: negative check with lengths. +@@ -8655,9 +8715,24 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> { + + MaybeObject* AsObject() { + if (hash_field_ == 0) Hash(); +- return HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_); ++ if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) { ++ while (true) { ++ Atomic32 my_symbol_id = next_symbol_id; ++ if (my_symbol_id > Smi::kMaxValue) ++ break; ++ if (my_symbol_id == NoBarrier_CompareAndSwap(&next_symbol_id, my_symbol_id, my_symbol_id + 1)) { ++ SeqString::cast(result->ToObjectUnchecked())->set_symbol_id(my_symbol_id); ++ break; ++ } ++ } ++ } ++ return result; + } ++ ++ static Atomic32 next_symbol_id; + }; ++Atomic32 AsciiSymbolKey::next_symbol_id = 1; + + + class TwoByteSymbolKey : public SequentialSymbolKey<uc16> { +diff --git a/src/objects.h b/src/objects.h +index e966b3d..6e26f57 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -5359,6 +5359,9 @@ class String: public HeapObject { + bool IsAsciiEqualTo(Vector<const char> str); + bool IsTwoByteEqualTo(Vector<const uc16> str); + ++ bool SlowEqualsExternal(uc16 *string, int length); ++ bool SlowEqualsExternal(char *string, int length); ++ + // Return a UTF8 representation of the string. The string is null + // terminated but may optionally contain nulls. Length is returned + // in length_output if length_output is not a null pointer The string +@@ -5610,9 +5613,17 @@ class String: public HeapObject { + class SeqString: public String { + public: + ++ // Get and set the symbol id of the string ++ inline int symbol_id(); ++ inline void set_symbol_id(int value); ++ + // Casting. + static inline SeqString* cast(Object* obj); + ++ // Layout description. ++ static const int kSymbolIdOffset = String::kSize; ++ static const int kSize = kSymbolIdOffset + kPointerSize; ++ + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); + }; +@@ -5647,7 +5658,7 @@ class SeqAsciiString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential ASCII string. +@@ -5701,7 +5712,7 @@ class SeqTwoByteString: public SeqString { + } + + // Layout description. +- static const int kHeaderSize = String::kSize; ++ static const int kHeaderSize = SeqString::kSize; + static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize); + + // Maximal memory usage for a single sequential two-byte string. +-- +1.7.2.3 + diff --git a/src/v8/0002-Add-a-bit-field-3-to-Map.patch b/src/v8/0002-Add-a-bit-field-3-to-Map.patch new file mode 100644 index 0000000000..dda9fa0dff --- /dev/null +++ b/src/v8/0002-Add-a-bit-field-3-to-Map.patch @@ -0,0 +1,118 @@ +From 7c9cfff80b7864d5687432d424074e51712c4a07 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 15:55:26 +1000 +Subject: [PATCH 02/13] Add a bit field 3 to Map + +Bit field 3 will be used to add QML specific map flags. +--- + src/heap.cc | 2 ++ + src/objects-inl.h | 10 ++++++++++ + src/objects.cc | 2 ++ + src/objects.h | 9 ++++++++- + 4 files changed, 22 insertions(+), 1 deletions(-) + +diff --git a/src/heap.cc b/src/heap.cc +index 930c97b..900f462 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -1573,6 +1573,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, + reinterpret_cast<Map*>(result)->set_unused_property_fields(0); + reinterpret_cast<Map*>(result)->set_bit_field(0); + reinterpret_cast<Map*>(result)->set_bit_field2(0); ++ reinterpret_cast<Map*>(result)->set_bit_field3(0); + return result; + } + +@@ -1599,6 +1600,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) { + map->set_unused_property_fields(0); + map->set_bit_field(0); + map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements)); ++ map->set_bit_field3(0); + + // If the map object is aligned fill the padding area with Smi 0 objects. + if (Map::kPadStart < Map::kSize) { +diff --git a/src/objects-inl.h b/src/objects-inl.h +index c82080d..cce3edd 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2430,6 +2430,16 @@ void Map::set_bit_field2(byte value) { + } + + ++byte Map::bit_field3() { ++ return READ_BYTE_FIELD(this, kBitField3Offset); ++} ++ ++ ++void Map::set_bit_field3(byte value) { ++ WRITE_BYTE_FIELD(this, kBitField3Offset, value); ++} ++ ++ + void Map::set_non_instance_prototype(bool value) { + if (value) { + set_bit_field(bit_field() | (1 << kHasNonInstancePrototype)); +diff --git a/src/objects.cc b/src/objects.cc +index dc4b260..79d7240 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -3614,6 +3614,7 @@ MaybeObject* Map::CopyDropDescriptors() { + } + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + Map::cast(result)->set_is_shared(false); + Map::cast(result)->ClearCodeCache(heap); + return result; +@@ -3642,6 +3643,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, + + Map::cast(result)->set_bit_field(bit_field()); + Map::cast(result)->set_bit_field2(bit_field2()); ++ Map::cast(result)->set_bit_field3(bit_field3()); + + Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); + +diff --git a/src/objects.h b/src/objects.h +index 6e26f57..07e1089 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -3597,6 +3597,10 @@ class Map: public HeapObject { + inline byte bit_field2(); + inline void set_bit_field2(byte value); + ++ // Bit field 3. ++ inline byte bit_field3(); ++ inline void set_bit_field3(byte value); ++ + // Tells whether the object in the prototype property will be used + // for instances created from this function. If the prototype + // property is set to a value that is not a JSObject, the prototype +@@ -3844,7 +3848,7 @@ class Map: public HeapObject { + // Layout description. + static const int kInstanceSizesOffset = HeapObject::kHeaderSize; + static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize; +- static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize; ++ static const int kPrototypeOffset = POINTER_SIZE_ALIGN(kInstanceAttributesOffset + 2 * kIntSize); + static const int kConstructorOffset = kPrototypeOffset + kPointerSize; + static const int kInstanceDescriptorsOffset = + kConstructorOffset + kPointerSize; +@@ -3876,6 +3880,7 @@ class Map: public HeapObject { + static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1; + static const int kBitFieldOffset = kInstanceAttributesOffset + 2; + static const int kBitField2Offset = kInstanceAttributesOffset + 3; ++ static const int kBitField3Offset = kInstanceAttributesOffset + 4; + + STATIC_CHECK(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset); + +@@ -3898,6 +3903,8 @@ class Map: public HeapObject { + static const int kIsShared = 5; + static const int kHasExternalArrayElements = 6; + ++ // Bit positions for bit field 3 ++ + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; + static const int kCodeCacheEntryNameOffset = 0; +-- +1.7.2.3 + diff --git a/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch new file mode 100644 index 0000000000..50f97c7de8 --- /dev/null +++ b/src/v8/0003-Add-a-fallback-mode-for-named-property-interceptors.patch @@ -0,0 +1,364 @@ +From ae8688b53d67044f2c9b0cce25fc282b078610c1 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 16:21:02 +1000 +Subject: [PATCH 03/13] Add a "fallback" mode for named property interceptors + +By default interceptors are called before the normal property +resolution on objects. When an interceptor is installed as a +"fallback" interceptor, it is only called if the object doesn't +already have the property. + +In the case of a global object having an fallback interceptor, +the interceptor is not invoked at all for var or function +declarations. +--- + include/v8.h | 8 ++++++++ + src/api.cc | 29 +++++++++++++++++++++++++++++ + src/factory.cc | 4 ++++ + src/handles.cc | 6 ++++-- + src/handles.h | 3 ++- + src/objects-inl.h | 16 ++++++++++++++++ + src/objects.cc | 22 ++++++++++++++++------ + src/objects.h | 18 ++++++++++++++---- + src/runtime.cc | 11 ++++++----- + 9 files changed, 99 insertions(+), 18 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index bbd29e9..85452aa 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2169,6 +2169,7 @@ class V8EXPORT FunctionTemplate : public Template { + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle<Value> data); + void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, + IndexedPropertySetter setter, +@@ -2253,6 +2254,13 @@ class V8EXPORT ObjectTemplate : public Template { + NamedPropertyEnumerator enumerator = 0, + Handle<Value> data = Handle<Value>()); + ++ void SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter = 0, ++ NamedPropertyQuery query = 0, ++ NamedPropertyDeleter deleter = 0, ++ NamedPropertyEnumerator enumerator = 0, ++ Handle<Value> data = Handle<Value>()); ++ + /** + * Sets an indexed property handler on the object template. + * +diff --git a/src/api.cc b/src/api.cc +index 381935b..8b0b32a 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, ++ bool is_fallback, + Handle<Value> data) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + if (IsDeadCheck(isolate, +@@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( + if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); + if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); + if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); ++ obj->set_is_fallback(i::Smi::FromInt(is_fallback)); + + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); +@@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, + query, + remover, + enumerator, ++ false, ++ data); ++} ++ ++ ++void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter, ++ NamedPropertySetter setter, ++ NamedPropertyQuery query, ++ NamedPropertyDeleter remover, ++ NamedPropertyEnumerator enumerator, ++ Handle<Value> data) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ EnsureConstructor(this); ++ i::FunctionTemplateInfo* constructor = ++ i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); ++ i::Handle<i::FunctionTemplateInfo> cons(constructor); ++ Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter, ++ setter, ++ query, ++ remover, ++ enumerator, ++ true, + data); + } + +diff --git a/src/factory.cc b/src/factory.cc +index 7dee66f..dcdc645 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -1058,6 +1058,10 @@ Handle<JSFunction> Factory::CreateApiFunction( + // Set interceptor information in the map. + if (!obj->named_property_handler()->IsUndefined()) { + map->set_has_named_interceptor(); ++ ++ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler()); ++ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value(); ++ map->set_named_interceptor_is_fallback(is_fallback); + } + if (!obj->indexed_property_handler()->IsUndefined()) { + map->set_has_indexed_interceptor(); +diff --git a/src/handles.cc b/src/handles.cc +index 326de86..dd3a86c 100644 +--- a/src/handles.cc ++++ b/src/handles.cc +@@ -262,9 +262,11 @@ Handle<Object> SetProperty(Handle<JSObject> object, + Handle<String> key, + Handle<Object> value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + CALL_HEAP_FUNCTION(object->GetIsolate(), +- object->SetProperty(*key, *value, attributes, strict_mode), ++ object->SetProperty(*key, *value, attributes, strict_mode, ++ skip_fallback_interceptor), + Object); + } + +diff --git a/src/handles.h b/src/handles.h +index 3839f37..4b42506 100644 +--- a/src/handles.h ++++ b/src/handles.h +@@ -188,7 +188,8 @@ Handle<Object> SetProperty(Handle<JSObject> object, + Handle<String> key, + Handle<Object> value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + + Handle<Object> SetProperty(Handle<Object> object, + Handle<Object> key, +diff --git a/src/objects-inl.h b/src/objects-inl.h +index cce3edd..6aaca2f 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2521,6 +2521,21 @@ bool Map::is_shared() { + } + + ++void Map::set_named_interceptor_is_fallback(bool value) ++{ ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback)); ++ } ++} ++ ++bool Map::named_interceptor_is_fallback() ++{ ++ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0; ++} ++ ++ + JSFunction* Map::unchecked_constructor() { + return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset)); + } +@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) + ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) + ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) + ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ++ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset) + + ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) + ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) +diff --git a/src/objects.cc b/src/objects.cc +index 79d7240..15e2cdb 100644 +--- a/src/objects.cc ++++ b/src/objects.cc +@@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( + MaybeObject* JSObject::SetProperty(String* name, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor) { + LookupResult result; +- LocalLookup(name, &result); ++ LocalLookup(name, &result, skip_fallback_interceptor); + return SetProperty(&result, name, value, attributes, strict_mode); + } + +@@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { + } + + +-void JSObject::LocalLookup(String* name, LookupResult* result) { ++void JSObject::LocalLookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + ASSERT(name->IsString()); + + Heap* heap = GetHeap(); +@@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) { + } + + // Check for lookup interceptor except when bootstrapping. +- if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { ++ bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive(); ++ if (wouldIntercept && !map()->named_interceptor_is_fallback()) { + result->InterceptorResult(this); + return; + } + + LocalLookupRealNamedProperty(name, result); ++ ++ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() && ++ map()->named_interceptor_is_fallback()) { ++ result->InterceptorResult(this); ++ return; ++ } + } + + +-void JSObject::Lookup(String* name, LookupResult* result) { ++void JSObject::Lookup(String* name, LookupResult* result, ++ bool skip_fallback_interceptor) { + // Ecma-262 3rd 8.6.2.4 + Heap* heap = GetHeap(); + for (Object* current = this; + current != heap->null_value(); + current = JSObject::cast(current)->GetPrototype()) { +- JSObject::cast(current)->LocalLookup(name, result); ++ JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor); + if (result->IsProperty()) return; + } + result->NotFound(); +diff --git a/src/objects.h b/src/objects.h +index 07e1089..a209cd0 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1405,7 +1405,8 @@ class JSObject: public HeapObject { + MUST_USE_RESULT MaybeObject* SetProperty(String* key, + Object* value, + PropertyAttributes attributes, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool skip_fallback_interceptor = false); + MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, + String* key, + Object* value, +@@ -1637,8 +1638,8 @@ class JSObject: public HeapObject { + + // Lookup a property. If found, the result is valid and has + // detailed information. +- void LocalLookup(String* name, LookupResult* result); +- void Lookup(String* name, LookupResult* result); ++ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); ++ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); + + // The following lookup functions skip interceptors. + void LocalLookupRealNamedProperty(String* name, LookupResult* result); +@@ -3714,6 +3715,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Whether the named interceptor is a fallback interceptor or not ++ inline void set_named_interceptor_is_fallback(bool value); ++ inline bool named_interceptor_is_fallback(); ++ ++ + // [prototype]: implicit prototype object. + DECL_ACCESSORS(prototype, Object) + +@@ -3904,6 +3911,7 @@ class Map: public HeapObject { + static const int kHasExternalArrayElements = 6; + + // Bit positions for bit field 3 ++ static const int kNamedInterceptorIsFallback = 0; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct { + DECL_ACCESSORS(deleter, Object) + DECL_ACCESSORS(enumerator, Object) + DECL_ACCESSORS(data, Object) ++ DECL_ACCESSORS(is_fallback, Smi) + + static inline InterceptorInfo* cast(Object* obj); + +@@ -6295,7 +6304,8 @@ class InterceptorInfo: public Struct { + static const int kDeleterOffset = kQueryOffset + kPointerSize; + static const int kEnumeratorOffset = kDeleterOffset + kPointerSize; + static const int kDataOffset = kEnumeratorOffset + kPointerSize; +- static const int kSize = kDataOffset + kPointerSize; ++ static const int kFallbackOffset = kDataOffset + kPointerSize; ++ static const int kSize = kFallbackOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); +diff --git a/src/runtime.cc b/src/runtime.cc +index 7335da8..660352c 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + // Lookup the property in the global object, and don't set the + // value of the variable if the property is already there. + LookupResult lookup; +- global->Lookup(*name, &lookup); ++ global->Lookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if the property is local by comparing the holder + // against the global object. The information will be used to +@@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + } + + LookupResult lookup; +- global->LocalLookup(*name, &lookup); ++ global->LocalLookup(*name, &lookup, true); + + PropertyAttributes attributes = is_const_property + ? static_cast<PropertyAttributes>(base | READ_ONLY) +@@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + name, + value, + attributes, +- strict_mode)); ++ strict_mode, ++ true)); + } + } + +@@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + JSObject* real_holder = global; + LookupResult lookup; + while (true) { +- real_holder->LocalLookup(*name, &lookup); ++ real_holder->LocalLookup(*name, &lookup, true); + if (lookup.IsProperty()) { + // Determine if this is a redeclaration of something read-only. + if (lookup.IsReadOnly()) { +@@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + + global = isolate->context()->global(); + if (assign) { +- return global->SetProperty(*name, args[2], attributes, strict_mode); ++ return global->SetProperty(*name, args[2], attributes, strict_mode, true); + } + return isolate->heap()->undefined_value(); + } +-- +1.7.2.3 + diff --git a/src/v8/0004-Generalize-external-object-resources.patch b/src/v8/0004-Generalize-external-object-resources.patch new file mode 100644 index 0000000000..f44e7b2134 --- /dev/null +++ b/src/v8/0004-Generalize-external-object-resources.patch @@ -0,0 +1,894 @@ +From 4827116b12c50f6662794017c5a662b5dbb2da0b Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 16:55:35 +1000 +Subject: [PATCH 04/13] Generalize external object resources + +V8 was already able to manage and finalize an external string +resource. This change generalizes that mechanism to handle a +single generic external resource - a v8::Object::ExternalResource +derived instance - on normal JSObject's. + +This is useful for mapping C++ objects to JS objects where the +C++ object's memory is effectively owned by the JS Object, and +thus needs to destroyed when the JS Object is garbage collected. +The V8 mailing list suggests using a weak persistent handle for +this purpose, but that seems to incur a fairly massive performance +penalty for short lived objects as weak persistent handle callbacks +are not called until the object has been promoted into the old +object space. +--- + include/v8.h | 25 ++++++ + src/api.cc | 64 ++++++++++++++- + src/extensions/externalize-string-extension.cc | 4 +- + src/factory.cc | 11 +++ + src/heap-inl.h | 101 +++++++++++++++--------- + src/heap.cc | 68 ++++++++-------- + src/heap.h | 42 +++++----- + src/liveobjectlist.cc | 4 +- + src/mark-compact.cc | 21 +++--- + src/objects-inl.h | 41 +++++++++- + src/objects.h | 14 +++- + 11 files changed, 280 insertions(+), 115 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 85452aa..7f06ae7 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1630,6 +1630,25 @@ class Object : public Value { + /** Sets a native pointer in an internal field. */ + V8EXPORT void SetPointerInInternalField(int index, void* value); + ++ class V8EXPORT ExternalResource { // NOLINT ++ public: ++ ExternalResource() {} ++ virtual ~ExternalResource() {} ++ ++ protected: ++ virtual void Dispose() { delete this; } ++ ++ private: ++ // Disallow copying and assigning. ++ ExternalResource(const ExternalResource&); ++ void operator=(const ExternalResource&); ++ ++ friend class v8::internal::Heap; ++ }; ++ ++ V8EXPORT void SetExternalResource(ExternalResource *); ++ V8EXPORT ExternalResource *GetExternalResource(); ++ + // Testers for local properties. + V8EXPORT bool HasRealNamedProperty(Handle<String> key); + V8EXPORT bool HasRealIndexedProperty(uint32_t index); +@@ -2331,6 +2350,12 @@ class V8EXPORT ObjectTemplate : public Template { + */ + void SetInternalFieldCount(int value); + ++ /** ++ * Sets whether the object can store an "external resource" object. ++ */ ++ bool HasExternalResource(); ++ void SetHasExternalResource(bool value); ++ + private: + ObjectTemplate(); + static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor); +diff --git a/src/api.cc b/src/api.cc +index 8b0b32a..1a6fbbb 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1294,6 +1294,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) { + } + + ++bool ObjectTemplate::HasExternalResource() ++{ ++ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(), ++ "v8::ObjectTemplate::HasExternalResource()")) { ++ return 0; ++ } ++ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined(); ++} ++ ++ ++void ObjectTemplate::SetHasExternalResource(bool value) ++{ ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ if (value) { ++ EnsureConstructor(this); ++ } ++ if (value) { ++ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1)); ++ } else { ++ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value()); ++ } ++} ++ ++ + // --- S c r i p t D a t a --- + + +@@ -3652,6 +3680,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { + } + + ++void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ENTER_V8(isolate); ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ if (CanBeEncodedAsSmi(resource)) { ++ obj->SetExternalResourceObject(EncodeAsSmi(resource)); ++ } else { ++ obj->SetExternalResourceObject(*isolate->factory()->NewProxy(static_cast<i::Address>((void *)resource))); ++ } ++ if (!obj->IsSymbol()) { ++ isolate->heap()->external_resource_table()->AddObject(*obj); ++ } ++} ++ ++ ++v8::Object::ExternalResource *v8::Object::GetExternalResource() { ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ i::Object* value = obj->GetExternalResourceObject(); ++ if (value->IsSmi()) { ++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Proxy::cast(value)->proxy()); ++ } else { ++ return NULL; ++ } ++} ++ ++ + // --- E n v i r o n m e n t --- + + +@@ -4144,7 +4200,7 @@ Local<String> v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle<i::String> result = NewExternalStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4162,7 +4218,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +@@ -4175,7 +4231,7 @@ Local<String> v8::String::NewExternal( + LOG_API(isolate, "String::NewExternal"); + ENTER_V8(isolate); + i::Handle<i::String> result = NewExternalAsciiStringHandle(isolate, resource); +- isolate->heap()->external_string_table()->AddString(*result); ++ isolate->heap()->external_resource_table()->AddString(*result); + return Utils::ToLocal(result); + } + +@@ -4194,7 +4250,7 @@ bool v8::String::MakeExternal( + } + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { +- isolate->heap()->external_string_table()->AddString(*obj); ++ isolate->heap()->external_resource_table()->AddString(*obj); + } + return result; + } +diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc +index b3f83fe..8e50904 100644 +--- a/src/extensions/externalize-string-extension.cc ++++ b/src/extensions/externalize-string-extension.cc +@@ -100,7 +100,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } else { +@@ -110,7 +110,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize( + data, string->length()); + result = string->MakeExternal(resource); + if (result && !string->IsSymbol()) { +- HEAP->external_string_table()->AddString(*string); ++ HEAP->external_resource_table()->AddString(*string); + } + if (!result) delete resource; + } +diff --git a/src/factory.cc b/src/factory.cc +index dcdc645..d530a75 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -997,15 +997,21 @@ Handle<JSFunction> Factory::CreateApiFunction( + Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi(); + + int internal_field_count = 0; ++ bool has_external_resource = false; ++ + if (!obj->instance_template()->IsUndefined()) { + Handle<ObjectTemplateInfo> instance_template = + Handle<ObjectTemplateInfo>( + ObjectTemplateInfo::cast(obj->instance_template())); + internal_field_count = + Smi::cast(instance_template->internal_field_count())->value(); ++ has_external_resource = ++ !instance_template->has_external_resource()->IsUndefined(); + } + + int instance_size = kPointerSize * internal_field_count; ++ if (has_external_resource) instance_size += kPointerSize; ++ + InstanceType type = INVALID_TYPE; + switch (instance_type) { + case JavaScriptObject: +@@ -1040,6 +1046,11 @@ Handle<JSFunction> Factory::CreateApiFunction( + + Handle<Map> map = Handle<Map>(result->initial_map()); + ++ // Mark as having external data object if needed ++ if (has_external_resource) { ++ map->set_has_external_resource(true); ++ } ++ + // Mark as undetectable if needed. + if (obj->undetectable()) { + map->set_is_undetectable(); +diff --git a/src/heap-inl.h b/src/heap-inl.h +index f4fce7b..58e7adf 100644 +--- a/src/heap-inl.h ++++ b/src/heap-inl.h +@@ -205,21 +205,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) { + } + + +-void Heap::FinalizeExternalString(String* string) { +- ASSERT(string->IsExternalString()); +- v8::String::ExternalStringResourceBase** resource_addr = +- reinterpret_cast<v8::String::ExternalStringResourceBase**>( +- reinterpret_cast<byte*>(string) + +- ExternalString::kResourceOffset - +- kHeapObjectTag); +- +- // Dispose of the C++ object if it has not already been disposed. +- if (*resource_addr != NULL) { +- (*resource_addr)->Dispose(); +- } ++void Heap::FinalizeExternalString(HeapObject* string) { ++ ASSERT(string->IsExternalString() || string->map()->has_external_resource()); ++ ++ if (string->IsExternalString()) { ++ v8::String::ExternalStringResourceBase** resource_addr = ++ reinterpret_cast<v8::String::ExternalStringResourceBase**>( ++ reinterpret_cast<byte*>(string) + ++ ExternalString::kResourceOffset - ++ kHeapObjectTag); ++ ++ // Dispose of the C++ object if it has not already been disposed. ++ if (*resource_addr != NULL) { ++ (*resource_addr)->Dispose(); ++ } + +- // Clear the resource pointer in the string. +- *resource_addr = NULL; ++ // Clear the resource pointer in the string. ++ *resource_addr = NULL; ++ } else { ++ JSObject *object = JSObject::cast(string); ++ Object *value = object->GetExternalResourceObject(); ++ v8::Object::ExternalResource *resource = 0; ++ if (value->IsSmi()) { ++ resource = reinterpret_cast<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsProxy()) { ++ resource = reinterpret_cast<v8::Object::ExternalResource*>(Proxy::cast(value)->proxy()); ++ } ++ if (resource) { ++ resource->Dispose(); ++ } ++ } + } + + +@@ -556,53 +571,63 @@ inline bool Heap::allow_allocation(bool new_state) { + #endif + + +-void ExternalStringTable::AddString(String* string) { +- ASSERT(string->IsExternalString()); ++void ExternalResourceTable::AddString(String* string) { ++ ASSERT(string->IsExternalString() ); + if (heap_->InNewSpace(string)) { +- new_space_strings_.Add(string); ++ new_space_objects_.Add(string); ++ } else { ++ old_space_objects_.Add(string); ++ } ++} ++ ++ ++void ExternalResourceTable::AddObject(HeapObject* object) { ++ ASSERT(object->map()->has_external_resource()); ++ if (heap_->InNewSpace(object)) { ++ new_space_objects_.Add(object); + } else { +- old_space_strings_.Add(string); ++ old_space_objects_.Add(object); + } + } + + +-void ExternalStringTable::Iterate(ObjectVisitor* v) { +- if (!new_space_strings_.is_empty()) { +- Object** start = &new_space_strings_[0]; +- v->VisitPointers(start, start + new_space_strings_.length()); ++void ExternalResourceTable::Iterate(ObjectVisitor* v) { ++ if (!new_space_objects_.is_empty()) { ++ Object** start = &new_space_objects_[0]; ++ v->VisitPointers(start, start + new_space_objects_.length()); + } +- if (!old_space_strings_.is_empty()) { +- Object** start = &old_space_strings_[0]; +- v->VisitPointers(start, start + old_space_strings_.length()); ++ if (!old_space_objects_.is_empty()) { ++ Object** start = &old_space_objects_[0]; ++ v->VisitPointers(start, start + old_space_objects_.length()); + } + } + + + // Verify() is inline to avoid ifdef-s around its calls in release + // mode. +-void ExternalStringTable::Verify() { ++void ExternalResourceTable::Verify() { + #ifdef DEBUG +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- ASSERT(heap_->InNewSpace(new_space_strings_[i])); +- ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ ASSERT(heap_->InNewSpace(new_space_objects_[i])); ++ ASSERT(new_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_null_value()); ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ ASSERT(old_space_objects_[i] != HEAP->raw_unchecked_null_value()); + } + #endif + } + + +-void ExternalStringTable::AddOldString(String* string) { +- ASSERT(string->IsExternalString()); +- ASSERT(!heap_->InNewSpace(string)); +- old_space_strings_.Add(string); ++void ExternalResourceTable::AddOldObject(HeapObject* object) { ++ ASSERT(object->IsExternalString() || object->map()->has_external_resource()); ++ ASSERT(!heap_->InNewSpace(object)); ++ old_space_objects_.Add(object); + } + + +-void ExternalStringTable::ShrinkNewStrings(int position) { +- new_space_strings_.Rewind(position); ++void ExternalResourceTable::ShrinkNewObjects(int position) { ++ new_space_objects_.Rewind(position); + Verify(); + } + +diff --git a/src/heap.cc b/src/heap.cc +index 900f462..bf2940e 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -155,7 +155,7 @@ Heap::Heap() + memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); + global_contexts_list_ = NULL; + mark_compact_collector_.heap_ = this; +- external_string_table_.heap_ = this; ++ external_resource_table_.heap_ = this; + } + + +@@ -1030,8 +1030,8 @@ void Heap::Scavenge() { + + new_space_front = DoScavenge(&scavenge_visitor, new_space_front); + +- UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + LiveObjectList::UpdateReferencesForScavengeGC(); + isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); +@@ -1053,38 +1053,38 @@ void Heap::Scavenge() { + } + + +-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++HeapObject* Heap::UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + MapWord first_word = HeapObject::cast(*p)->map_word(); + + if (!first_word.IsForwardingAddress()) { + // Unreachable external string can be finalized. +- heap->FinalizeExternalString(String::cast(*p)); ++ heap->FinalizeExternalString(HeapObject::cast(*p)); + return NULL; + } + + // String is still reachable. +- return String::cast(first_word.ToForwardingAddress()); ++ return HeapObject::cast(first_word.ToForwardingAddress()); + } + + +-void Heap::UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func) { +- external_string_table_.Verify(); ++void Heap::UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func) { ++ external_resource_table_.Verify(); + +- if (external_string_table_.new_space_strings_.is_empty()) return; ++ if (external_resource_table_.new_space_objects_.is_empty()) return; + +- Object** start = &external_string_table_.new_space_strings_[0]; +- Object** end = start + external_string_table_.new_space_strings_.length(); ++ Object** start = &external_resource_table_.new_space_objects_[0]; ++ Object** end = start + external_resource_table_.new_space_objects_.length(); + Object** last = start; + + for (Object** p = start; p < end; ++p) { + ASSERT(InFromSpace(*p)); +- String* target = updater_func(this, p); ++ HeapObject* target = updater_func(this, p); + + if (target == NULL) continue; + +- ASSERT(target->IsExternalString()); ++ ASSERT(target->IsExternalString() || target->map()->has_external_resource()); + + if (InNewSpace(target)) { + // String is still in new space. Update the table entry. +@@ -1092,12 +1092,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable( + ++last; + } else { + // String got promoted. Move it to the old string list. +- external_string_table_.AddOldString(target); ++ external_resource_table_.AddOldObject(target); + } + } + + ASSERT(last <= end); +- external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); ++ external_resource_table_.ShrinkNewObjects(static_cast<int>(last - start)); + } + + +@@ -4468,7 +4468,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { + v->Synchronize("symbol_table"); + if (mode != VISIT_ALL_IN_SCAVENGE) { + // Scavenge collections have special processing for this. +- external_string_table_.Iterate(v); ++ external_resource_table_.Iterate(v); + } + v->Synchronize("external_string_table"); + } +@@ -4970,7 +4970,7 @@ void Heap::TearDown() { + + isolate_->global_handles()->TearDown(); + +- external_string_table_.TearDown(); ++ external_resource_table_.TearDown(); + + new_space_.TearDown(); + +@@ -5835,31 +5835,31 @@ void TranscendentalCache::Clear() { + } + + +-void ExternalStringTable::CleanUp() { ++void ExternalResourceTable::CleanUp() { + int last = 0; +- for (int i = 0; i < new_space_strings_.length(); ++i) { +- if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- if (heap_->InNewSpace(new_space_strings_[i])) { +- new_space_strings_[last++] = new_space_strings_[i]; ++ for (int i = 0; i < new_space_objects_.length(); ++i) { ++ if (new_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ if (heap_->InNewSpace(new_space_objects_[i])) { ++ new_space_objects_[last++] = new_space_objects_[i]; + } else { +- old_space_strings_.Add(new_space_strings_[i]); ++ old_space_objects_.Add(new_space_objects_[i]); + } + } +- new_space_strings_.Rewind(last); ++ new_space_objects_.Rewind(last); + last = 0; +- for (int i = 0; i < old_space_strings_.length(); ++i) { +- if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; +- ASSERT(!heap_->InNewSpace(old_space_strings_[i])); +- old_space_strings_[last++] = old_space_strings_[i]; ++ for (int i = 0; i < old_space_objects_.length(); ++i) { ++ if (old_space_objects_[i] == heap_->raw_unchecked_null_value()) continue; ++ ASSERT(!heap_->InNewSpace(old_space_objects_[i])); ++ old_space_objects_[last++] = old_space_objects_[i]; + } +- old_space_strings_.Rewind(last); ++ old_space_objects_.Rewind(last); + Verify(); + } + + +-void ExternalStringTable::TearDown() { +- new_space_strings_.Free(); +- old_space_strings_.Free(); ++void ExternalResourceTable::TearDown() { ++ new_space_objects_.Free(); ++ old_space_objects_.Free(); + } + + +diff --git a/src/heap.h b/src/heap.h +index ae4e9e7..8cbf378 100644 +--- a/src/heap.h ++++ b/src/heap.h +@@ -237,8 +237,8 @@ class Isolate; + class WeakObjectRetainer; + + +-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap, +- Object** pointer); ++typedef HeapObject* (*ExternalResourceTableUpdaterCallback)(Heap* heap, ++ Object** pointer); + + typedef bool (*DirtyRegionCallback)(Heap* heap, + Address start, +@@ -284,43 +284,45 @@ class PromotionQueue { + }; + + +-// External strings table is a place where all external strings are +-// registered. We need to keep track of such strings to properly +-// finalize them. +-class ExternalStringTable { ++// External resource table is a place where all external strings and ++// objects with an external resource are registered. We need to keep ++// track of such strings to properly finalize them. ++class ExternalResourceTable { + public: + // Registers an external string. + inline void AddString(String* string); ++ // Registers an external object. ++ inline void AddObject(HeapObject* object); + + inline void Iterate(ObjectVisitor* v); + + // Restores internal invariant and gets rid of collected strings. +- // Must be called after each Iterate() that modified the strings. ++ // Must be called after each Iterate() that modified the objects. + void CleanUp(); + + // Destroys all allocated memory. + void TearDown(); + + private: +- ExternalStringTable() { } ++ ExternalResourceTable() { } + + friend class Heap; + + inline void Verify(); + +- inline void AddOldString(String* string); ++ inline void AddOldObject(HeapObject* object); + + // Notifies the table that only a prefix of the new list is valid. +- inline void ShrinkNewStrings(int position); ++ inline void ShrinkNewObjects(int position); + + // To speed up scavenge collections new space string are kept + // separate from old space strings. +- List<Object*> new_space_strings_; +- List<Object*> old_space_strings_; ++ List<Object*> new_space_objects_; ++ List<Object*> old_space_objects_; + + Heap* heap_; + +- DISALLOW_COPY_AND_ASSIGN(ExternalStringTable); ++ DISALLOW_COPY_AND_ASSIGN(ExternalResourceTable); + }; + + +@@ -753,7 +755,7 @@ class Heap { + + // Finalizes an external string by deleting the associated external + // data and clearing the resource pointer. +- inline void FinalizeExternalString(String* string); ++ inline void FinalizeExternalString(HeapObject* string); + + // Allocates an uninitialized object. The memory is non-executable if the + // hardware and OS allow. +@@ -1191,8 +1193,8 @@ class Heap { + survived_since_last_expansion_ += survived; + } + +- void UpdateNewSpaceReferencesInExternalStringTable( +- ExternalStringTableUpdaterCallback updater_func); ++ void UpdateNewSpaceReferencesInExternalResourceTable( ++ ExternalResourceTableUpdaterCallback updater_func); + + void ProcessWeakReferences(WeakObjectRetainer* retainer); + +@@ -1228,8 +1230,8 @@ class Heap { + return &mark_compact_collector_; + } + +- ExternalStringTable* external_string_table() { +- return &external_string_table_; ++ ExternalResourceTable* external_resource_table() { ++ return &external_resource_table_; + } + + inline Isolate* isolate(); +@@ -1462,7 +1464,7 @@ class Heap { + // Performs a minor collection in new generation. + void Scavenge(); + +- static String* UpdateNewSpaceReferenceInExternalStringTableEntry( ++ static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry( + Heap* heap, + Object** pointer); + +@@ -1593,7 +1595,7 @@ class Heap { + // configured through the API until it is setup. + bool configured_; + +- ExternalStringTable external_string_table_; ++ ExternalResourceTable external_resource_table_; + + bool is_safe_to_read_maps_; + +diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc +index 5795a6b..8866e58 100644 +--- a/src/liveobjectlist.cc ++++ b/src/liveobjectlist.cc +@@ -1989,7 +1989,7 @@ Object* LiveObjectList::PrintObj(int obj_id) { + ASSERT(resource->IsAscii()); + Handle<String> dump_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*dump_string); ++ ExternalResourceTable::AddString(*dump_string); + return *dump_string; + } else { + delete resource; +@@ -2193,7 +2193,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) { + ASSERT(resource->IsAscii()); + Handle<String> path_string = + Factory::NewExternalStringFromAscii(resource); +- ExternalStringTable::AddString(*path_string); ++ ExternalResourceTable::AddString(*path_string); + return *path_string; + } else { + delete resource; +diff --git a/src/mark-compact.cc b/src/mark-compact.cc +index 68a5062..1b1e361 100644 +--- a/src/mark-compact.cc ++++ b/src/mark-compact.cc +@@ -163,7 +163,7 @@ void MarkCompactCollector::Finish() { + // objects (empty string, illegal builtin). + heap()->isolate()->stub_cache()->Clear(); + +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.CleanUp(); + + // If we've just compacted old space there's no reason to check the + // fragmentation limit. Just return. +@@ -1019,8 +1019,9 @@ class SymbolTableCleaner : public ObjectVisitor { + + // Since no objects have yet been moved we can safely access the map of + // the object. +- if ((*p)->IsExternalString()) { +- heap_->FinalizeExternalString(String::cast(*p)); ++ if ((*p)->IsExternalString() || ++ (*p)->IsHeapObject() && HeapObject::cast(*p)->map()->has_external_resource()) { ++ heap_->FinalizeExternalString(HeapObject::cast(*p)); + } + // Set the entry to null_value (as deleted). + *p = heap_->raw_unchecked_null_value(); +@@ -1433,8 +1434,8 @@ void MarkCompactCollector::MarkLiveObjects() { + SymbolTableCleaner v(heap()); + symbol_table->IterateElements(&v); + symbol_table->ElementsRemoved(v.PointersRemoved()); +- heap()->external_string_table_.Iterate(&v); +- heap()->external_string_table_.CleanUp(); ++ heap()->external_resource_table_.Iterate(&v); ++ heap()->external_resource_table_.CleanUp(); + + // Process the weak references. + MarkCompactWeakObjectRetainer mark_compact_object_retainer; +@@ -1948,11 +1949,11 @@ static void UpdatePointerToNewGen(HeapObject** p) { + } + + +-static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, +- Object** p) { ++static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap, ++ Object** p) { + Address old_addr = HeapObject::cast(*p)->address(); + Address new_addr = Memory::Address_at(old_addr); +- return String::cast(HeapObject::FromAddress(new_addr)); ++ return HeapObject::FromAddress(new_addr); + } + + +@@ -2083,8 +2084,8 @@ static void SweepNewSpace(Heap* heap, NewSpace* space) { + updating_visitor.VisitPointer(heap->global_contexts_list_address()); + + // Update pointers from external string table. +- heap->UpdateNewSpaceReferencesInExternalStringTable( +- &UpdateNewSpaceReferenceInExternalStringTableEntry); ++ heap->UpdateNewSpaceReferencesInExternalResourceTable( ++ &UpdateNewSpaceReferenceInExternalResourceTableEntry); + + // All pointers were updated. Update auxiliary allocation info. + heap->IncrementYoungSurvivorsCounter(survivors_size); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 6aaca2f..231b835 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -1392,13 +1392,13 @@ int JSObject::GetInternalFieldCount() { + // Make sure to adjust for the number of in-object properties. These + // properties do contribute to the size, but are not internal fields. + return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) - +- map()->inobject_properties(); ++ map()->inobject_properties() - map()->has_external_resource()?1:0; + } + + + int JSObject::GetInternalFieldOffset(int index) { + ASSERT(index < GetInternalFieldCount() && index >= 0); +- return GetHeaderSize() + (kPointerSize * index); ++ return GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + } + + +@@ -1407,7 +1407,7 @@ Object* JSObject::GetInternalField(int index) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index)); ++ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0))); + } + + +@@ -1416,12 +1416,29 @@ void JSObject::SetInternalField(int index, Object* value) { + // Internal objects do follow immediately after the header, whereas in-object + // properties are at the end of the object. Therefore there is no need + // to adjust the index here. +- int offset = GetHeaderSize() + (kPointerSize * index); ++ int offset = GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)); + WRITE_FIELD(this, offset, value); + WRITE_BARRIER(this, offset); + } + + ++void JSObject::SetExternalResourceObject(Object *value) { ++ ASSERT(map()->has_external_resource()); ++ int offset = GetHeaderSize(); ++ WRITE_FIELD(this, offset, value); ++ WRITE_BARRIER(this, offset); ++} ++ ++ ++Object *JSObject::GetExternalResourceObject() { ++ if (map()->has_external_resource()) { ++ return READ_FIELD(this, GetHeaderSize()); ++ } else { ++ return GetHeap()->undefined_value(); ++ } ++} ++ ++ + // Access fast-case object properties at index. The use of these routines + // is needed to correctly distinguish between properties stored in-object and + // properties stored in the properties array. +@@ -2521,6 +2538,20 @@ bool Map::is_shared() { + } + + ++void Map::set_has_external_resource(bool value) { ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kHasExternalResource)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kHasExternalResource)); ++ } ++} ++ ++bool Map::has_external_resource() ++{ ++ return ((1 << kHasExternalResource) & bit_field3()) != 0; ++} ++ ++ + void Map::set_named_interceptor_is_fallback(bool value) + { + if (value) { +@@ -3017,6 +3048,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) + ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) + ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) ++ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, ++ kHasExternalResourceOffset) + + ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) + ACCESSORS(SignatureInfo, args, Object, kArgsOffset) +diff --git a/src/objects.h b/src/objects.h +index a209cd0..1bdb5c7 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -1636,6 +1636,9 @@ class JSObject: public HeapObject { + inline Object* GetInternalField(int index); + inline void SetInternalField(int index, Object* value); + ++ inline void SetExternalResourceObject(Object *); ++ inline Object *GetExternalResourceObject(); ++ + // Lookup a property. If found, the result is valid and has + // detailed information. + void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); +@@ -3715,6 +3718,12 @@ class Map: public HeapObject { + inline void set_is_access_check_needed(bool access_check_needed); + inline bool is_access_check_needed(); + ++ ++ // Tells whether the instance has the space for an external resource ++ // object ++ inline void set_has_external_resource(bool value); ++ inline bool has_external_resource(); ++ + + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); +@@ -3912,6 +3921,7 @@ class Map: public HeapObject { + + // Bit positions for bit field 3 + static const int kNamedInterceptorIsFallback = 0; ++ static const int kHasExternalResource = 1; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6426,6 +6436,7 @@ class ObjectTemplateInfo: public TemplateInfo { + public: + DECL_ACCESSORS(constructor, Object) + DECL_ACCESSORS(internal_field_count, Object) ++ DECL_ACCESSORS(has_external_resource, Object) + + static inline ObjectTemplateInfo* cast(Object* obj); + +@@ -6442,7 +6453,8 @@ class ObjectTemplateInfo: public TemplateInfo { + static const int kConstructorOffset = TemplateInfo::kHeaderSize; + static const int kInternalFieldCountOffset = + kConstructorOffset + kPointerSize; +- static const int kSize = kInternalFieldCountOffset + kPointerSize; ++ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; ++ static const int kSize = kHasExternalResourceOffset + kPointerSize; + }; + + +-- +1.7.2.3 + diff --git a/src/v8/0005-Introduce-a-QML-compilation-mode.patch b/src/v8/0005-Introduce-a-QML-compilation-mode.patch new file mode 100644 index 0000000000..b464e61266 --- /dev/null +++ b/src/v8/0005-Introduce-a-QML-compilation-mode.patch @@ -0,0 +1,1777 @@ +From fd7d475e298e5b63cd6383c78cc900635c82aa38 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 18:26:19 +1000 +Subject: [PATCH 05/13] Introduce a QML compilation mode + +In QML mode, there is a second global object - known as the QML +global object. During property resolution, if a property is not +present on the JS global object, it is resolve on the QML global +object. + +This global object behavior is only enabled if a script is being +compiled in QML mode. The object to use as the QML global object +is passed as a parameter to the Script::Run() method. Any function +closures etc. created during the run will retain a reference to this +object, so different objects can be passed in different script +runs. +--- + include/v8.h | 18 ++++++++-- + src/api.cc | 52 ++++++++++++++++++++++++----- + src/arm/code-stubs-arm.cc | 4 ++ + src/arm/full-codegen-arm.cc | 26 ++++++++------ + src/arm/lithium-arm.cc | 2 +- + src/arm/lithium-arm.h | 6 +++- + src/arm/lithium-codegen-arm.cc | 7 ++-- + src/arm/macro-assembler-arm.h | 5 +++ + src/ast-inl.h | 5 +++ + src/ast.h | 1 + + src/code-stubs.h | 2 +- + src/compiler.cc | 15 +++++++- + src/compiler.h | 22 ++++++++++-- + src/contexts.cc | 23 +++++++++++++ + src/contexts.h | 4 ++ + src/execution.cc | 28 +++++++++++++-- + src/execution.h | 6 +++ + src/full-codegen.cc | 3 +- + src/full-codegen.h | 1 + + src/heap.cc | 2 + + src/hydrogen-instructions.h | 10 ++++- + src/hydrogen.cc | 2 + + src/ia32/code-stubs-ia32.cc | 7 ++++ + src/ia32/full-codegen-ia32.cc | 26 ++++++++------ + src/ia32/lithium-codegen-ia32.cc | 7 ++-- + src/ia32/lithium-ia32.cc | 2 +- + src/ia32/lithium-ia32.h | 6 +++- + src/ia32/macro-assembler-ia32.h | 5 +++ + src/objects-inl.h | 12 +++++++ + src/objects.h | 5 +++ + src/parser.cc | 27 +++++++++++++-- + src/parser.h | 4 ++- + src/prettyprinter.cc | 3 ++ + src/runtime.cc | 68 ++++++++++++++++++++++++------------- + src/runtime.h | 8 ++-- + src/scopes.cc | 10 +++++ + src/scopes.h | 7 ++++ + src/variables.cc | 3 +- + src/variables.h | 5 +++ + src/x64/code-stubs-x64.cc | 4 ++ + src/x64/full-codegen-x64.cc | 26 ++++++++------ + src/x64/lithium-codegen-x64.cc | 7 ++-- + src/x64/lithium-x64.cc | 2 +- + src/x64/lithium-x64.h | 6 +++ + src/x64/macro-assembler-x64.h | 5 +++ + 45 files changed, 391 insertions(+), 108 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 7f06ae7..a858eae 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -577,6 +577,10 @@ class ScriptOrigin { + */ + class V8EXPORT Script { + public: ++ enum CompileFlags { ++ Default = 0x00, ++ QmlMode = 0x01 ++ }; + + /** + * Compiles the specified script (context-independent). +@@ -596,7 +600,8 @@ class V8EXPORT Script { + static Local<Script> New(Handle<String> source, + ScriptOrigin* origin = NULL, + ScriptData* pre_data = NULL, +- Handle<String> script_data = Handle<String>()); ++ Handle<String> script_data = Handle<String>(), ++ CompileFlags = Default); + + /** + * Compiles the specified script using the specified file name +@@ -609,7 +614,8 @@ class V8EXPORT Script { + * will use the currently entered context). + */ + static Local<Script> New(Handle<String> source, +- Handle<Value> file_name); ++ Handle<Value> file_name, ++ CompileFlags = Default); + + /** + * Compiles the specified script (bound to current context). +@@ -630,7 +636,8 @@ class V8EXPORT Script { + static Local<Script> Compile(Handle<String> source, + ScriptOrigin* origin = NULL, + ScriptData* pre_data = NULL, +- Handle<String> script_data = Handle<String>()); ++ Handle<String> script_data = Handle<String>(), ++ CompileFlags = Default); + + /** + * Compiles the specified script using the specified file name +@@ -647,7 +654,8 @@ class V8EXPORT Script { + */ + static Local<Script> Compile(Handle<String> source, + Handle<Value> file_name, +- Handle<String> script_data = Handle<String>()); ++ Handle<String> script_data = Handle<String>(), ++ CompileFlags = Default); + + /** + * Runs the script returning the resulting value. If the script is +@@ -657,6 +665,7 @@ class V8EXPORT Script { + * compiled. + */ + Local<Value> Run(); ++ Local<Value> Run(Handle<Object> qml); + + /** + * Returns the script id value. +@@ -3326,6 +3335,7 @@ class V8EXPORT Context { + * JavaScript frames an empty handle is returned. + */ + static Local<Context> GetCalling(); ++ static Local<Object> GetCallingQmlGlobal(); + + /** + * Sets the security token for the context. To access an object in +diff --git a/src/api.cc b/src/api.cc +index 1a6fbbb..39767f4 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1372,7 +1372,8 @@ ScriptData* ScriptData::New(const char* data, int length) { + Local<Script> Script::New(v8::Handle<String> source, + v8::ScriptOrigin* origin, + v8::ScriptData* pre_data, +- v8::Handle<String> script_data) { ++ v8::Handle<String> script_data, ++ v8::Script::CompileFlags compile_flags) { + i::Isolate* isolate = i::Isolate::Current(); + ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>()); + LOG_API(isolate, "Script::New"); +@@ -1409,7 +1410,8 @@ Local<Script> Script::New(v8::Handle<String> source, + NULL, + pre_data_impl, + Utils::OpenHandle(*script_data), +- i::NOT_NATIVES_CODE); ++ i::NOT_NATIVES_CODE, ++ compile_flags); + has_pending_exception = result.is_null(); + EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>()); + return Local<Script>(ToApi<Script>(result)); +@@ -1417,21 +1419,23 @@ Local<Script> Script::New(v8::Handle<String> source, + + + Local<Script> Script::New(v8::Handle<String> source, +- v8::Handle<Value> file_name) { ++ v8::Handle<Value> file_name, ++ v8::Script::CompileFlags compile_flags) { + ScriptOrigin origin(file_name); +- return New(source, &origin); ++ return New(source, &origin, 0, Handle<String>(), compile_flags); + } + + + Local<Script> Script::Compile(v8::Handle<String> source, + v8::ScriptOrigin* origin, + v8::ScriptData* pre_data, +- v8::Handle<String> script_data) { ++ v8::Handle<String> script_data, ++ v8::Script::CompileFlags compile_flags) { + i::Isolate* isolate = i::Isolate::Current(); + ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>()); + LOG_API(isolate, "Script::Compile"); + ENTER_V8(isolate); +- Local<Script> generic = New(source, origin, pre_data, script_data); ++ Local<Script> generic = New(source, origin, pre_data, script_data, compile_flags); + if (generic.IsEmpty()) + return generic; + i::Handle<i::Object> obj = Utils::OpenHandle(*generic); +@@ -1447,13 +1451,18 @@ Local<Script> Script::Compile(v8::Handle<String> source, + + Local<Script> Script::Compile(v8::Handle<String> source, + v8::Handle<Value> file_name, +- v8::Handle<String> script_data) { ++ v8::Handle<String> script_data, ++ v8::Script::CompileFlags compile_flags) { + ScriptOrigin origin(file_name); +- return Compile(source, &origin, 0, script_data); ++ return Compile(source, &origin, 0, script_data, compile_flags); + } + + + Local<Value> Script::Run() { ++ return Run(Handle<Object>()); ++} ++ ++Local<Value> Script::Run(Handle<Object> qml) { + i::Isolate* isolate = i::Isolate::Current(); + ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>()); + LOG_API(isolate, "Script::Run"); +@@ -1472,10 +1481,11 @@ Local<Value> Script::Run() { + fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate); + } + EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> qmlglobal = Utils::OpenHandle(*qml); + i::Handle<i::Object> receiver( + isolate->context()->global_proxy(), isolate); + i::Handle<i::Object> result = +- i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception); ++ i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception, qmlglobal); + EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); + raw_result = *result; + } +@@ -3943,6 +3953,30 @@ v8::Local<v8::Context> Context::GetCalling() { + } + + ++v8::Local<v8::Object> Context::GetCallingQmlGlobal() { ++ i::Isolate* isolate = i::Isolate::Current(); ++ if (IsDeadCheck(isolate, "v8::Context::GetCallingQmlGlobal()")) { ++ return Local<Object>(); ++ } ++ ++ i::Context *context = isolate->context(); ++ if (!context->qml_global()->IsUndefined()) { ++ i::Handle<i::Object> qmlglobal(context->qml_global()); ++ return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal)); ++ } ++ ++ i::JavaScriptFrameIterator it; ++ if (it.done()) return Local<Object>(); ++ context = i::Context::cast(it.frame()->context()); ++ if (!context->qml_global()->IsUndefined()) { ++ i::Handle<i::Object> qmlglobal(context->qml_global()); ++ return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal)); ++ } else { ++ return Local<Object>(); ++ } ++} ++ ++ + v8::Local<v8::Object> Context::Global() { + if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) { + return Local<v8::Object>(); +diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc +index 8c147f9..a2626bf 100644 +--- a/src/arm/code-stubs-arm.cc ++++ b/src/arm/code-stubs-arm.cc +@@ -166,6 +166,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { + __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ str(r1, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX))); + ++ // Copy the qml global object from the surrounding context. ++ __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); ++ __ str(r1, MemOperand(r0, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); ++ + // Initialize the rest of the slots to undefined. + __ 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..a69f10d 100644 +--- a/src/arm/full-codegen-arm.cc ++++ b/src/arm/full-codegen-arm.cc +@@ -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); + } + +- __ ldr(r0, GlobalObjectOperand()); ++ __ ldr(r0, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(r2, Operand(slot->var()->name())); +- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global()) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +@@ -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. +- __ ldr(r0, GlobalObjectOperand()); ++ __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(r2, Operand(var->name())); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(r0); + + } else if (slot != NULL && slot->type() == Slot::LOOKUP) { +@@ -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())); +- __ ldr(r1, GlobalObjectOperand()); ++ __ ldr(r1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + Handle<Code> ic = is_strict_mode() + ? isolate()->builtins()->StoreIC_Initialize_Strict() + : isolate()->builtins()->StoreIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function +@@ -2184,10 +2185,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, + // Push the strict mode flag. + __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); + __ push(r1); ++ // Push the qml mode flag. ++ __ mov(r1, Operand(Smi::FromInt(is_qml_mode()))); ++ __ push(r1); + + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP + ? Runtime::kResolvePossiblyDirectEvalNoLookup +- : Runtime::kResolvePossiblyDirectEval, 4); ++ : Runtime::kResolvePossiblyDirectEval, 5); + } + + +@@ -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. +- __ ldr(r0, GlobalObjectOperand()); ++ __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ push(r0); +- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + } 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 ++++ b/src/arm/macro-assembler-arm.h +@@ -1056,6 +1056,11 @@ static inline MemOperand GlobalObjectOperand() { + } + + ++static inline MemOperand QmlGlobalObjectOperand() { ++ return ContextOperand(cp, Context::QML_GLOBAL_INDEX); ++} ++ ++ + #ifdef GENERATED_CODE_COVERAGE + #define CODE_COVERAGE_STRINGIFY(x) #x + #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) +diff --git a/src/ast-inl.h b/src/ast-inl.h +index d80684a..adc5a1f 100644 +--- a/src/ast-inl.h ++++ b/src/ast-inl.h +@@ -106,6 +106,11 @@ bool FunctionLiteral::strict_mode() const { + } + + ++bool FunctionLiteral::qml_mode() const { ++ return scope()->is_qml_mode(); ++} ++ ++ + } } // namespace v8::internal + + #endif // V8_AST_INL_H_ +diff --git a/src/ast.h b/src/ast.h +index 65a25a9..f790dc0 100644 +--- a/src/ast.h ++++ b/src/ast.h +@@ -1712,6 +1712,7 @@ class FunctionLiteral: public Expression { + int end_position() const { return end_position_; } + bool is_expression() const { return is_expression_; } + bool strict_mode() const; ++ bool qml_mode() const; + + 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 ++++ b/src/compiler.cc +@@ -462,7 +462,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + v8::Extension* extension, + ScriptDataImpl* input_pre_data, + Handle<Object> script_data, +- NativesFlag natives) { ++ NativesFlag natives, ++ v8::Script::CompileFlags compile_flags) { + Isolate* isolate = source->GetIsolate(); + int source_length = source->length(); + isolate->counters()->total_load_size()->Increment(source_length); +@@ -523,6 +524,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + info.MarkAsGlobal(); + info.SetExtension(extension); + info.SetPreParseData(pre_data); ++ if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode(); + if (natives == NATIVES_CODE) info.MarkAsAllowingNativesSyntax(); + result = MakeFunctionInfo(&info); + if (extension == NULL && !result.is_null()) { +@@ -543,7 +545,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, + Handle<Context> context, + bool is_global, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + Isolate* isolate = source->GetIsolate(); + int source_length = source->length(); + isolate->counters()->total_eval_size()->Increment(source_length); +@@ -567,6 +570,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, + CompilationInfo info(script); + info.MarkAsEval(); + if (is_global) info.MarkAsGlobal(); ++ if (qml_mode) info.MarkAsQmlMode(); + if (strict_mode == kStrictMode) info.MarkAsStrictMode(); + info.SetCallingContext(context); + result = MakeFunctionInfo(&info); +@@ -610,6 +614,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) { + info->MarkAsStrictMode(); + } + ++ // After parsing we know function's qml mode. Remember it. ++ if (info->function()->qml_mode()) { ++ shared->set_qml_mode(true); ++ info->MarkAsQmlMode(); ++ } ++ + // Compile the code. + if (!MakeCode(info)) { + if (!isolate->has_pending_exception()) { +@@ -755,6 +765,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, + *lit->this_property_assignments()); + function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); + function_info->set_strict_mode(lit->strict_mode()); ++ function_info->set_qml_mode(lit->qml_mode()); + } + + +diff --git a/src/compiler.h b/src/compiler.h +index e75e869..17cd369 100644 +--- a/src/compiler.h ++++ b/src/compiler.h +@@ -54,6 +54,7 @@ class CompilationInfo BASE_EMBEDDED { + bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; } + bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; } + bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; } ++ bool is_qml_mode() const { return (flags_ & IsQmlMode::mask()) != 0; } + FunctionLiteral* function() const { return function_; } + Scope* scope() const { return scope_; } + Handle<Code> code() const { return code_; } +@@ -83,6 +84,9 @@ class CompilationInfo BASE_EMBEDDED { + ASSERT(is_lazy()); + flags_ |= IsInLoop::encode(true); + } ++ void MarkAsQmlMode() { ++ flags_ |= IsQmlMode::encode(true); ++ } + void MarkAsAllowingNativesSyntax() { + flags_ |= IsNativesSyntaxAllowed::encode(true); + } +@@ -141,6 +145,7 @@ class CompilationInfo BASE_EMBEDDED { + + // Determine whether or not we can adaptively optimize. + bool AllowOptimize() { ++ // XXX - fix qml mode optimizations + return V8::UseCrankshaft() && !closure_.is_null(); + } + +@@ -163,8 +168,13 @@ class CompilationInfo BASE_EMBEDDED { + + void Initialize(Mode mode) { + mode_ = V8::UseCrankshaft() ? mode : NONOPT; +- if (!shared_info_.is_null() && shared_info_->strict_mode()) { +- MarkAsStrictMode(); ++ if (!shared_info_.is_null()) { ++ if (shared_info_->strict_mode()) { ++ MarkAsStrictMode(); ++ } ++ if (shared_info_->qml_mode()) { ++ MarkAsQmlMode(); ++ } + } + } + +@@ -187,6 +197,8 @@ class CompilationInfo BASE_EMBEDDED { + class IsStrictMode: public BitField<bool, 4, 1> {}; + // Native syntax (%-stuff) allowed? + class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {}; ++ // Qml mode ++ class IsQmlMode: public BitField<bool, 6, 1> {}; + + unsigned flags_; + +@@ -252,13 +264,15 @@ class Compiler : public AllStatic { + v8::Extension* extension, + ScriptDataImpl* pre_data, + Handle<Object> script_data, +- NativesFlag is_natives_code); ++ NativesFlag is_natives_code, ++ v8::Script::CompileFlags compile_flags = v8::Script::Default); + + // Compile a String source within a context for Eval. + static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, + Handle<Context> context, + bool is_global, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool qml_mode); + + // Compile from function info (used for lazy compilation). Returns true on + // success and false if the compilation resulted in a stack overflow. +diff --git a/src/contexts.cc b/src/contexts.cc +index 520f3dd..da5cacb 100644 +--- a/src/contexts.cc ++++ b/src/contexts.cc +@@ -89,6 +89,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + PrintF(")\n"); + } + ++ Handle<JSObject> qml_global; ++ + do { + if (FLAG_trace_contexts) { + PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); +@@ -119,6 +121,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + } + } + ++ if (qml_global.is_null() && !context->qml_global()->IsUndefined()) { ++ qml_global = Handle<JSObject>(context->qml_global(), isolate); ++ } ++ + if (context->is_function_context()) { + // we have context-local slots + +@@ -198,6 +204,23 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + } + } while (follow_context_chain); + ++ if (!qml_global.is_null()) { ++ if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) { ++ *attributes = qml_global->GetLocalPropertyAttribute(*name); ++ } else { ++ *attributes = qml_global->GetPropertyAttribute(*name); ++ } ++ ++ if (*attributes != ABSENT) { ++ // property found ++ if (FLAG_trace_contexts) { ++ PrintF("=> found property in qml global object %p\n", ++ reinterpret_cast<void*>(*qml_global)); ++ } ++ return qml_global; ++ } ++ } ++ + // slot not found + if (FLAG_trace_contexts) { + PrintF("=> no property/slot found\n"); +diff --git a/src/contexts.h b/src/contexts.h +index e46619e..57d8e7b 100644 +--- a/src/contexts.h ++++ b/src/contexts.h +@@ -182,6 +182,7 @@ class Context: public FixedArray { + FCONTEXT_INDEX, + PREVIOUS_INDEX, + EXTENSION_INDEX, ++ QML_GLOBAL_INDEX, + GLOBAL_INDEX, + MIN_CONTEXT_SLOTS, + +@@ -273,6 +274,9 @@ class Context: public FixedArray { + } + void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); } + ++ JSObject *qml_global() { return reinterpret_cast<JSObject *>(get(QML_GLOBAL_INDEX)); } ++ void set_qml_global(JSObject *qml_global) { set(QML_GLOBAL_INDEX, qml_global); } ++ + // Returns a JSGlobalProxy object or null. + JSObject* global_proxy(); + void set_global_proxy(JSObject* global); +diff --git a/src/execution.cc b/src/execution.cc +index eb26438..1632076 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -70,7 +70,8 @@ static Handle<Object> Invoke(bool construct, + Handle<Object> receiver, + int argc, + Object*** args, +- bool* has_pending_exception) { ++ bool* has_pending_exception, ++ Handle<Object> qml) { + Isolate* isolate = func->GetIsolate(); + + // Entering JavaScript. +@@ -107,6 +108,12 @@ static Handle<Object> Invoke(bool construct, + // make the current one is indeed a global object. + ASSERT(func->context()->global()->IsGlobalObject()); + ++ Handle<JSObject> oldqml; ++ if (!qml.is_null()) { ++ oldqml = Handle<JSObject>(func->context()->qml_global()); ++ func->context()->set_qml_global(JSObject::cast(*qml)); ++ } ++ + { + // Save and restore context around invocation and block the + // allocation of handles without explicit handle scopes. +@@ -122,6 +129,9 @@ static Handle<Object> Invoke(bool construct, + receiver_pointer, argc, args); + } + ++ if (!qml.is_null()) ++ func->context()->set_qml_global(*oldqml); ++ + #ifdef DEBUG + value->Verify(); + #endif +@@ -150,14 +160,24 @@ Handle<Object> Execution::Call(Handle<JSFunction> func, + int argc, + Object*** args, + bool* pending_exception) { +- return Invoke(false, func, receiver, argc, args, pending_exception); ++ return Invoke(false, func, receiver, argc, args, pending_exception, Handle<Object>()); ++} ++ ++ ++Handle<Object> Execution::Call(Handle<JSFunction> func, ++ Handle<Object> receiver, ++ int argc, ++ Object*** args, ++ bool* pending_exception, ++ Handle<Object> qml) { ++ return Invoke(false, func, receiver, argc, args, pending_exception, qml); + } + + + Handle<Object> Execution::New(Handle<JSFunction> func, int argc, + Object*** args, bool* pending_exception) { + return Invoke(true, func, Isolate::Current()->global(), argc, args, +- pending_exception); ++ pending_exception, Handle<Object>()); + } + + +@@ -175,7 +195,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func, + catcher.SetCaptureMessage(false); + + Handle<Object> result = Invoke(false, func, receiver, argc, args, +- caught_exception); ++ caught_exception, Handle<Object>()); + + if (*caught_exception) { + ASSERT(catcher.HasCaught()); +diff --git a/src/execution.h b/src/execution.h +index d4b80d2..a476eb4 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -56,6 +56,12 @@ class Execution : public AllStatic { + int argc, + Object*** args, + bool* pending_exception); ++ static Handle<Object> Call(Handle<JSFunction> func, ++ Handle<Object> receiver, ++ int argc, ++ Object*** args, ++ bool* pending_exception, ++ Handle<Object> qml); + + // Construct object from function, the caller supplies an array of + // arguments. Arguments are Object* type. After function returns, +diff --git a/src/full-codegen.cc b/src/full-codegen.cc +index d6ba56e..2eaef0f 100644 +--- a/src/full-codegen.cc ++++ b/src/full-codegen.cc +@@ -542,7 +542,7 @@ void FullCodeGenerator::VisitDeclarations( + // Do nothing in case of no declared global functions or variables. + if (globals > 0) { + Handle<FixedArray> array = +- isolate()->factory()->NewFixedArray(2 * globals, TENURED); ++ isolate()->factory()->NewFixedArray(3 * globals, TENURED); + for (int j = 0, i = 0; i < length; i++) { + Declaration* decl = declarations->at(i); + Variable* var = decl->proxy()->var(); +@@ -567,6 +567,7 @@ void FullCodeGenerator::VisitDeclarations( + } + array->set(j++, *function); + } ++ array->set(j++, Smi::FromInt(var->is_qml_global())); + } + } + // Invoke the platform-dependent code generator to do the actual +diff --git a/src/full-codegen.h b/src/full-codegen.h +index d6ed1b9..e3241aa 100644 +--- a/src/full-codegen.h ++++ b/src/full-codegen.h +@@ -505,6 +505,7 @@ class FullCodeGenerator: public AstVisitor { + StrictModeFlag strict_mode_flag() { + return is_strict_mode() ? kStrictMode : kNonStrictMode; + } ++ bool is_qml_mode() { return function()->qml_mode(); } + FunctionLiteral* function() { return info_->function(); } + Scope* scope() { return info_->scope(); } + +diff --git a/src/heap.cc b/src/heap.cc +index bf2940e..da958c2 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -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()); ++ context->set_qml_global(function->context()->qml_global()); + ASSERT(!context->IsGlobalContext()); + ASSERT(context->is_function_context()); + ASSERT(result->IsContext()); +@@ -3817,6 +3818,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous, + context->set_previous(previous); + context->set_extension(extension); + context->set_global(previous->global()); ++ context->set_qml_global(previous->qml_global()); + 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 ++++ b/src/ia32/code-stubs-ia32.cc +@@ -147,6 +147,13 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { + __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); + ++ // Copy the qml global object from the surrounding context. We go through the ++ // context in the function (ecx) to match the allocation behavior we have ++ // in the runtime system (see Heap::AllocateFunctionContext). ++ __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset)); ++ __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); ++ __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), ebx); ++ + // Initialize the rest of the slots to undefined. + __ 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..0ddcde2 100644 +--- a/src/ia32/full-codegen-ia32.cc ++++ b/src/ia32/full-codegen-ia32.cc +@@ -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. +- __ mov(eax, GlobalObjectOperand()); ++ __ mov(eax, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(ecx, slot->var()->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global()) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + EmitCallIC(ic, mode); +@@ -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. +- __ mov(eax, GlobalObjectOperand()); ++ __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(ecx, var->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(eax); + + } else if (slot != NULL && slot->type() == Slot::LOOKUP) { +@@ -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()); +- __ mov(edx, GlobalObjectOperand()); ++ __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + Handle<Code> ic = is_strict_mode() + ? isolate()->builtins()->StoreIC_Initialize_Strict() + : isolate()->builtins()->StoreIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function +@@ -2113,9 +2114,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, + // Push the strict mode flag. + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + ++ // Push the qml mode flag ++ __ push(Immediate(Smi::FromInt(is_qml_mode()))); ++ + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP + ? Runtime::kResolvePossiblyDirectEvalNoLookup +- : Runtime::kResolvePossiblyDirectEval, 4); ++ : Runtime::kResolvePossiblyDirectEval, 5); + } + + +@@ -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. +- __ push(GlobalObjectOperand()); +- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); ++ __ push(var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); ++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + } 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 ++++ b/src/ia32/macro-assembler-ia32.h +@@ -778,6 +778,11 @@ static inline Operand GlobalObjectOperand() { + } + + ++static inline Operand QmlGlobalObjectOperand() { ++ return ContextOperand(esi, Context::QML_GLOBAL_INDEX); ++} ++ ++ + // Generates an Operand for saving parameters after PrepareCallApiFunction. + Operand ApiParameterOperand(int index); + +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 231b835..1c7f83e 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -3242,6 +3242,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) { + } + + ++bool SharedFunctionInfo::qml_mode() { ++ return BooleanBit::get(compiler_hints(), kQmlModeFunction); ++} ++ ++ ++void SharedFunctionInfo::set_qml_mode(bool value) { ++ set_compiler_hints(BooleanBit::set(compiler_hints(), ++ kQmlModeFunction, ++ value)); ++} ++ ++ + ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset) + ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset) + +diff --git a/src/objects.h b/src/objects.h +index 1bdb5c7..edbc47a 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -4331,6 +4331,10 @@ class SharedFunctionInfo: public HeapObject { + inline bool strict_mode(); + inline void set_strict_mode(bool value); + ++ // Indicates whether the function is a qml mode function ++ inline bool qml_mode(); ++ inline void set_qml_mode(bool value); ++ + // Indicates whether or not the code in the shared function support + // deoptimization. + inline bool has_deoptimization_support(); +@@ -4511,6 +4515,7 @@ class SharedFunctionInfo: public HeapObject { + static const int kCodeAgeMask = 0x7; + static const int kOptimizationDisabled = 6; + static const int kStrictModeFunction = 7; ++ static const int kQmlModeFunction = 8; + + private: + #if V8_HOST_ARCH_32_BIT +diff --git a/src/parser.cc b/src/parser.cc +index a84ec6f..7f5c361 100644 +--- a/src/parser.cc ++++ b/src/parser.cc +@@ -593,7 +593,8 @@ Parser::Parser(Handle<Script> script, + + FunctionLiteral* Parser::ParseProgram(Handle<String> source, + bool in_global_context, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); + + HistogramTimerScope timer(isolate()->counters()->parse()); +@@ -609,11 +610,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, + ExternalTwoByteStringUC16CharacterStream stream( + Handle<ExternalTwoByteString>::cast(source), 0, source->length()); + scanner_.Initialize(&stream); +- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); ++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope); + } else { + GenericStringUC16CharacterStream stream(source, 0, source->length()); + scanner_.Initialize(&stream); +- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); ++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope); + } + } + +@@ -621,6 +622,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, + FunctionLiteral* Parser::DoParseProgram(Handle<String> source, + bool in_global_context, + StrictModeFlag strict_mode, ++ bool qml_mode, + ZoneScope* zone_scope) { + ASSERT(target_stack_ == NULL); + if (pre_data_ != NULL) pre_data_->Initialize(); +@@ -641,6 +643,9 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, + if (strict_mode == kStrictMode) { + top_scope_->EnableStrictMode(); + } ++ if (qml_mode) { ++ scope->EnableQmlMode(); ++ } + ZoneList<Statement*>* body = new ZoneList<Statement*>(16); + bool ok = true; + int beg_loc = scanner().location().beg_pos; +@@ -729,6 +734,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, + if (shared_info->strict_mode()) { + top_scope_->EnableStrictMode(); + } ++ if (shared_info->qml_mode()) { ++ top_scope_->EnableQmlMode(); ++ } + + FunctionLiteralType type = + shared_info->is_expression() ? EXPRESSION : DECLARATION; +@@ -1661,6 +1669,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, + arguments->Add(value); + value = NULL; // zap the value to avoid the unnecessary assignment + ++ int qml_mode = 0; ++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) ++ qml_mode = 1; ++ arguments->Add(NewNumberLiteral(qml_mode)); ++ + // Construct the call to Runtime_InitializeConstGlobal + // and add it to the initialization statement block. + // Note that the function does different things depending on +@@ -1676,6 +1689,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, + arguments->Add(NewNumberLiteral( + top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode)); + ++ int qml_mode = 0; ++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) ++ qml_mode = 1; ++ arguments->Add(NewNumberLiteral(qml_mode)); ++ + // Be careful not to assign a value to the global variable if + // we're in a with. The initialization value should not + // necessarily be stored in the global object in that case, +@@ -5157,7 +5175,8 @@ bool ParserApi::Parse(CompilationInfo* info) { + Handle<String> source = Handle<String>(String::cast(script->source())); + result = parser.ParseProgram(source, + info->is_global(), +- info->StrictMode()); ++ info->StrictMode(), ++ info->is_qml_mode()); + } + } + +diff --git a/src/parser.h b/src/parser.h +index 64f1303..4d45e45 100644 +--- a/src/parser.h ++++ b/src/parser.h +@@ -431,7 +431,8 @@ class Parser { + // Returns NULL if parsing failed. + FunctionLiteral* ParseProgram(Handle<String> source, + bool in_global_context, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool qml_mode); + + FunctionLiteral* ParseLazy(CompilationInfo* info); + +@@ -464,6 +465,7 @@ class Parser { + FunctionLiteral* DoParseProgram(Handle<String> source, + bool in_global_context, + StrictModeFlag strict_mode, ++ bool qml_mode, + ZoneScope* zone_scope); + + // Report syntax error +diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc +index c777ab4..1964e02 100644 +--- a/src/prettyprinter.cc ++++ b/src/prettyprinter.cc +@@ -656,6 +656,9 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, + EmbeddedVector<char, 256> buf; + int pos = OS::SNPrintF(buf, "%s (mode = %s", info, + Variable::Mode2String(var->mode())); ++ if (var->is_qml_global()) { ++ pos += OS::SNPrintF(buf + pos, ":QML"); ++ } + OS::SNPrintF(buf + pos, ")"); + PrintLiteralIndented(buf.start(), value, true); + } +diff --git a/src/runtime.cc b/src/runtime.cc +index 660352c..827d954 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -1065,8 +1065,6 @@ static Failure* ThrowRedeclarationError(Isolate* isolate, + RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + ASSERT(args.length() == 4); + HandleScope scope(isolate); +- Handle<GlobalObject> global = Handle<GlobalObject>( +- isolate->context()->global()); + + Handle<Context> context = args.at<Context>(0); + CONVERT_ARG_CHECKED(FixedArray, pairs, 1); +@@ -1075,6 +1073,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + static_cast<StrictModeFlag>(Smi::cast(args[3])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); + ++ Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global()); ++ Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global()); ++ + // Compute the property attributes. According to ECMA-262, section + // 13, page 71, the property must be read-only and + // non-deletable. However, neither SpiderMonkey nor KJS creates the +@@ -1083,10 +1084,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + + // Traverse the name/value pairs and set the properties. + int length = pairs->length(); +- for (int i = 0; i < length; i += 2) { ++ for (int i = 0; i < length; i += 3) { + HandleScope scope(isolate); + Handle<String> name(String::cast(pairs->get(i))); + Handle<Object> value(pairs->get(i + 1), isolate); ++ Handle<Smi> is_qml_global(Smi::cast(pairs->get(i + 2))); ++ ++ Handle<JSObject> global = is_qml_global->value()?qml_global:js_global; + + // We have to declare a global const property. To capture we only + // assign to it when evaluating the assignment for "const x = +@@ -1316,20 +1320,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + NoHandleAllocation nha; + // args[0] == name + // args[1] == strict_mode +- // args[2] == value (optional) ++ // args[2] == qml_mode ++ // args[3] == value (optional) + + // Determine if we need to assign to the variable if it already + // exists (based on the number of arguments). +- RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); +- bool assign = args.length() == 3; ++ RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); ++ bool assign = args.length() == 4; + + CONVERT_ARG_CHECKED(String, name, 0); +- GlobalObject* global = isolate->context()->global(); + RUNTIME_ASSERT(args[1]->IsSmi()); + StrictModeFlag strict_mode = + static_cast<StrictModeFlag>(Smi::cast(args[1])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); + ++ RUNTIME_ASSERT(args[2]->IsSmi()); ++ int qml_mode = Smi::cast(args[2])->value(); ++ ++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global(); ++ + // According to ECMA-262, section 12.2, page 62, the property must + // not be deletable. + PropertyAttributes attributes = DONT_DELETE; +@@ -1350,7 +1359,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + if (lookup.IsReadOnly()) { + // If we found readonly property on one of hidden prototypes, + // just shadow it. +- if (real_holder != isolate->context()->global()) break; ++ if (real_holder != global) break; + return ThrowRedeclarationError(isolate, "const", name); + } + +@@ -1372,7 +1381,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + // overwrite it with a variable declaration we must throw a + // re-declaration error. However if we found readonly property + // on one of hidden prototypes, just shadow it. +- if (real_holder != isolate->context()->global()) break; ++ if (real_holder != global) break; + return ThrowRedeclarationError(isolate, "const", name); + } + } +@@ -1384,7 +1393,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + } + + // Assign the value (or undefined) to the property. +- Object* value = (assign) ? args[2] : isolate->heap()->undefined_value(); ++ Object* value = (assign) ? args[3] : isolate->heap()->undefined_value(); + return real_holder->SetProperty( + &lookup, *name, value, attributes, strict_mode); + } +@@ -1399,9 +1408,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + real_holder = JSObject::cast(proto); + } + +- global = isolate->context()->global(); ++ global = qml_mode?isolate->context()->qml_global():isolate->context()->global(); + if (assign) { +- return global->SetProperty(*name, args[2], attributes, strict_mode, true); ++ return global->SetProperty(*name, args[3], attributes, strict_mode, true); + } + return isolate->heap()->undefined_value(); + } +@@ -1411,12 +1420,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { + // All constants are declared with an initial value. The name + // of the constant is the first argument and the initial value + // is the second. +- RUNTIME_ASSERT(args.length() == 2); ++ RUNTIME_ASSERT(args.length() == 3); + CONVERT_ARG_CHECKED(String, name, 0); + Handle<Object> value = args.at<Object>(1); + ++ RUNTIME_ASSERT(args[2]->IsSmi()); ++ int qml_mode = Smi::cast(args[2])->value(); ++ + // Get the current global object from top. +- GlobalObject* global = isolate->context()->global(); ++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global(); + + // According to ECMA-262, section 12.2, page 62, the property must + // not be deletable. Since it's a const, it must be READ_ONLY too. +@@ -1456,7 +1468,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { + // with setting the value because the property is either absent or + // read-only. We also have to do redo the lookup. + HandleScope handle_scope(isolate); +- Handle<GlobalObject> global(isolate->context()->global()); ++ Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global()); + + // BUG 1213575: Handle the case where we have to set a read-only + // property through an interceptor and only do it if it's +@@ -8160,7 +8172,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { + Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, + context, + true, +- kNonStrictMode); ++ kNonStrictMode, ++ false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, +@@ -8173,14 +8186,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { + static ObjectPair CompileGlobalEval(Isolate* isolate, + Handle<String> source, + Handle<Object> receiver, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + // Deal with a normal eval call with a string argument. Compile it + // and return the compiled function bound in the local context. + Handle<SharedFunctionInfo> shared = Compiler::CompileEval( + source, + Handle<Context>(isolate->context()), + isolate->context()->IsGlobalContext(), +- strict_mode); ++ strict_mode, ++ qml_mode); + if (shared.is_null()) return MakePair(Failure::Exception(), NULL); + Handle<JSFunction> compiled = + isolate->factory()->NewFunctionFromSharedFunctionInfo( +@@ -8190,7 +8205,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, + + + RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { +- ASSERT(args.length() == 4); ++ ASSERT(args.length() == 5); + + HandleScope scope(isolate); + Handle<Object> callee = args.at<Object>(0); +@@ -8257,16 +8272,18 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { + } + + ASSERT(args[3]->IsSmi()); ++ ASSERT(args[4]->IsSmi()); + return CompileGlobalEval(isolate, + args.at<String>(1), + args.at<Object>(2), + static_cast<StrictModeFlag>( +- Smi::cast(args[3])->value())); ++ Smi::cast(args[3])->value()), ++ Smi::cast(args[4])->value()); + } + + + RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) { +- ASSERT(args.length() == 4); ++ ASSERT(args.length() == 5); + + HandleScope scope(isolate); + Handle<Object> callee = args.at<Object>(0); +@@ -8280,11 +8297,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) { + } + + ASSERT(args[3]->IsSmi()); ++ ASSERT(args[4]->IsSmi()); + return CompileGlobalEval(isolate, + args.at<String>(1), + args.at<Object>(2), + static_cast<StrictModeFlag>( +- Smi::cast(args[3])->value())); ++ Smi::cast(args[3])->value()), ++ Smi::cast(args[4])->value()); + } + + +@@ -10633,7 +10652,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { + Compiler::CompileEval(function_source, + context, + context->IsGlobalContext(), +- kNonStrictMode); ++ kNonStrictMode, ++ false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> compiled_function = + isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); +@@ -10722,7 +10742,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { + // Currently, the eval code will be executed in non-strict mode, + // even in the strict code context. + Handle<SharedFunctionInfo> shared = +- Compiler::CompileEval(source, context, is_global, kNonStrictMode); ++ Compiler::CompileEval(source, context, is_global, kNonStrictMode, false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> compiled_function = + Handle<JSFunction>( +diff --git a/src/runtime.h b/src/runtime.h +index bf1ba68..5e97173 100644 +--- a/src/runtime.h ++++ b/src/runtime.h +@@ -241,8 +241,8 @@ namespace internal { + \ + /* Eval */ \ + F(GlobalReceiver, 1, 1) \ +- F(ResolvePossiblyDirectEval, 4, 2) \ +- F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \ ++ F(ResolvePossiblyDirectEval, 5, 2) \ ++ F(ResolvePossiblyDirectEvalNoLookup, 5, 2) \ + \ + F(SetProperty, -1 /* 4 or 5 */, 1) \ + F(DefineOrRedefineDataProperty, 4, 1) \ +@@ -296,8 +296,8 @@ namespace internal { + /* Declarations and initialization */ \ + F(DeclareGlobals, 4, 1) \ + F(DeclareContextSlot, 4, 1) \ +- F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ +- F(InitializeConstGlobal, 2, 1) \ ++ F(InitializeVarGlobal, -1 /* 3 or 4 */, 1) \ ++ F(InitializeConstGlobal, 3, 1) \ + F(InitializeConstContextSlot, 3, 1) \ + F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ + \ +diff --git a/src/scopes.cc b/src/scopes.cc +index 8df93c5..734a217 100644 +--- a/src/scopes.cc ++++ b/src/scopes.cc +@@ -198,6 +198,7 @@ void Scope::SetDefaults(Type type, + scope_calls_eval_ = false; + // Inherit the strict mode from the parent scope. + strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; ++ qml_mode_ = (outer_scope != NULL) && outer_scope->qml_mode_; + outer_scope_calls_eval_ = false; + inner_scope_calls_eval_ = false; + outer_scope_is_eval_scope_ = false; +@@ -796,6 +797,10 @@ void Scope::ResolveVariable(Scope* global_scope, + ASSERT(global_scope != NULL); + var = global_scope->DeclareGlobal(proxy->name()); + ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) { ++ var->set_is_qml_global(true); ++ } ++ + } else if (scope_inside_with_) { + // If we are inside a with statement we give up and look up + // the variable at runtime. +@@ -816,6 +821,8 @@ void Scope::ResolveVariable(Scope* global_scope, + // variables. + if (context->GlobalIfNotShadowedByEval(proxy->name())) { + var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) ++ var->set_is_qml_global(true); + + } else { + var = NonLocal(proxy->name(), Variable::DYNAMIC); +@@ -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); ++ ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) ++ var->set_is_qml_global(true); + } + } + } +diff --git a/src/scopes.h b/src/scopes.h +index a0e56a4..6dd3f65 100644 +--- a/src/scopes.h ++++ b/src/scopes.h +@@ -210,6 +210,11 @@ class Scope: public ZoneObject { + strict_mode_ = FLAG_strict_mode; + } + ++ // Enable qml mode for this scope ++ void EnableQmlMode() { ++ qml_mode_ = true; ++ } ++ + // --------------------------------------------------------------------------- + // Predicates. + +@@ -218,6 +223,7 @@ class Scope: public ZoneObject { + bool is_function_scope() const { return type_ == FUNCTION_SCOPE; } + bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } + bool is_strict_mode() const { return strict_mode_; } ++ bool is_qml_mode() const { return qml_mode_; } + + // Information about which scopes calls eval. + bool calls_eval() const { return scope_calls_eval_; } +@@ -376,6 +382,7 @@ class Scope: public ZoneObject { + bool scope_contains_with_; // this scope contains a 'with' statement + bool scope_calls_eval_; // this scope contains an 'eval' call + bool strict_mode_; // this scope is a strict mode scope ++ bool qml_mode_; // this scope is a qml mode scope + + // Computed via PropagateScopeInfo. + bool outer_scope_calls_eval_; +diff --git a/src/variables.cc b/src/variables.cc +index 0502722..190baf6 100644 +--- a/src/variables.cc ++++ b/src/variables.cc +@@ -99,7 +99,8 @@ Variable::Variable(Scope* scope, + rewrite_(NULL), + is_valid_LHS_(is_valid_LHS), + is_accessed_from_inner_scope_(false), +- is_used_(false) { ++ is_used_(false), ++ is_qml_global_(false) { + // names must be canonicalized for fast equality checks + ASSERT(name->IsSymbol()); + } +diff --git a/src/variables.h b/src/variables.h +index b1ff0db..0b31d1a 100644 +--- a/src/variables.h ++++ b/src/variables.h +@@ -141,6 +141,8 @@ class Variable: public ZoneObject { + Expression* rewrite() const { return rewrite_; } + void set_rewrite(Expression* expr) { rewrite_ = expr; } + ++ bool is_qml_global() const { return is_qml_global_; } ++ void set_is_qml_global(bool is_qml_global) { is_qml_global_ = is_qml_global; } + private: + Scope* scope_; + Handle<String> name_; +@@ -159,6 +161,9 @@ class Variable: public ZoneObject { + // Usage info. + bool is_accessed_from_inner_scope_; // set by variable resolver + bool is_used_; ++ ++ // QML info ++ bool is_qml_global_; + }; + + +diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc +index c365385..d923494 100644 +--- a/src/x64/code-stubs-x64.cc ++++ b/src/x64/code-stubs-x64.cc +@@ -140,6 +140,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { + __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); + ++ // Copy the qml global object from the surrounding context. ++ __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); ++ __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), rbx); ++ + // Initialize the rest of the slots to undefined. + __ 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..c45cdb6 100644 +--- a/src/x64/full-codegen-x64.cc ++++ b/src/x64/full-codegen-x64.cc +@@ -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. +- __ movq(rax, GlobalObjectOperand()); ++ __ movq(rax, slot->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); + __ Move(rcx, slot->var()->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global()) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + EmitCallIC(ic, mode); +@@ -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()); +- __ movq(rax, GlobalObjectOperand()); ++ __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(rax); + + } else if (slot != NULL && slot->type() == Slot::LOOKUP) { +@@ -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()); +- __ movq(rdx, GlobalObjectOperand()); ++ __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); + Handle<Code> ic = is_strict_mode() + ? isolate()->builtins()->StoreIC_Initialize_Strict() + : isolate()->builtins()->StoreIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function +@@ -2085,9 +2086,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, + // Push the strict mode flag. + __ Push(Smi::FromInt(strict_mode_flag())); + ++ // Push the qml mode flag ++ __ Push(Smi::FromInt(is_qml_mode())); ++ + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP + ? Runtime::kResolvePossiblyDirectEvalNoLookup +- : Runtime::kResolvePossiblyDirectEval, 4); ++ : Runtime::kResolvePossiblyDirectEval, 5); + } + + +@@ -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. +- __ push(GlobalObjectOperand()); +- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); ++ __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); ++ EmitCallWithIC(expr, var->name(), var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + } 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 ++++ b/src/x64/macro-assembler-x64.h +@@ -1233,6 +1233,11 @@ static inline Operand GlobalObjectOperand() { + } + + ++static inline Operand QmlGlobalObjectOperand() { ++ return ContextOperand(rsi, Context::QML_GLOBAL_INDEX); ++} ++ ++ + // Provides access to exit frame stack space (not GCed). + static inline Operand StackSpaceOperand(int index) { + #ifdef _WIN64 +-- +1.7.2.3 + 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 new file mode 100644 index 0000000000..d4acdf7a42 --- /dev/null +++ b/src/v8/0006-Allow-access-to-the-calling-script-data.patch @@ -0,0 +1,48 @@ +From f890f0d1a1e5bd62711815489c87755a4f382436 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Wed, 25 May 2011 10:36:13 +1000 +Subject: [PATCH 06/13] Allow access to the calling script data + +--- + include/v8.h | 1 + + src/api.cc | 12 ++++++++++++ + 2 files changed, 13 insertions(+), 0 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index a858eae..9aba4a8 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -3336,6 +3336,7 @@ class V8EXPORT Context { + */ + static Local<Context> GetCalling(); + static Local<Object> GetCallingQmlGlobal(); ++ static Local<Value> GetCallingScriptData(); + + /** + * Sets the security token for the context. To access an object in +diff --git a/src/api.cc b/src/api.cc +index 39767f4..ff74efb 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3976,6 +3976,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() { + } + } + ++v8::Local<v8::Value> Context::GetCallingScriptData() ++{ ++ i::Isolate* isolate = i::Isolate::Current(); ++ if (IsDeadCheck(isolate, "v8::Context::GetCallingScriptData()")) { ++ return Local<Object>(); ++ } ++ ++ i::JavaScriptFrameIterator it; ++ if (it.done()) return Local<Object>(); ++ i::Handle<i::Script> script(i::Script::cast(i::JSFunction::cast(it.frame()->function())->shared()->script())); ++ return Utils::ToLocal(i::Handle<i::Object>(script->data())); ++} + + v8::Local<v8::Object> Context::Global() { + if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) { +-- +1.7.2.3 + diff --git a/src/v8/0007-Fix-warnings.patch b/src/v8/0007-Fix-warnings.patch new file mode 100644 index 0000000000..26141c8ae8 --- /dev/null +++ b/src/v8/0007-Fix-warnings.patch @@ -0,0 +1,46 @@ +From dac5d9db84cf20564621c679937ca7b9c6a8e880 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Fri, 27 May 2011 13:04:15 +1000 +Subject: [PATCH 07/13] Fix warnings + +--- + include/v8.h | 16 ++++++++-------- + 1 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 9aba4a8..8891dab 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2415,7 +2415,7 @@ class V8EXPORT Extension { // NOLINT + const char** deps = 0); + virtual ~Extension() { } + virtual v8::Handle<v8::FunctionTemplate> +- GetNativeFunction(v8::Handle<v8::String> name) { ++ GetNativeFunction(v8::Handle<v8::String>) { + return v8::Handle<v8::FunctionTemplate>(); + } + +@@ -3721,13 +3721,13 @@ class Internals { + return *reinterpret_cast<T*>(addr); + } + +- static inline bool CanCastToHeapObject(void* o) { return false; } +- static inline bool CanCastToHeapObject(Context* o) { return true; } +- static inline bool CanCastToHeapObject(String* o) { return true; } +- static inline bool CanCastToHeapObject(Object* o) { return true; } +- static inline bool CanCastToHeapObject(Message* o) { return true; } +- static inline bool CanCastToHeapObject(StackTrace* o) { return true; } +- static inline bool CanCastToHeapObject(StackFrame* o) { return true; } ++ static inline bool CanCastToHeapObject(void*) { return false; } ++ static inline bool CanCastToHeapObject(Context*) { return true; } ++ static inline bool CanCastToHeapObject(String*) { return true; } ++ static inline bool CanCastToHeapObject(Object*) { return true; } ++ static inline bool CanCastToHeapObject(Message*) { return true; } ++ static inline bool CanCastToHeapObject(StackTrace*) { return true; } ++ static inline bool CanCastToHeapObject(StackFrame*) { return true; } + }; + + } // namespace internal +-- +1.7.2.3 + 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 0000000000..d7ef5c434d --- /dev/null +++ b/src/v8/0008-Add-custom-object-compare-callback.patch @@ -0,0 +1,489 @@ +From bec11b8b7f89d135e7d9a823ac4fe98c70d017cf Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 27 Jun 2011 14:57:28 +1000 +Subject: [PATCH 08/13] Add custom object compare callback + +A global custom object comparison callback can be set with: + V8::SetUserObjectComparisonCallbackFunction() +When two JSObjects are compared (== or !=), if either one has +the MarkAsUseUserObjectComparison() bit set, the custom comparison +callback is invoked to do the actual comparison. + +This is useful when you have "value" objects that you want to +compare as equal, even though they are actually different JS object +instances. +--- + include/v8.h | 13 +++++++++++++ + src/api.cc | 19 +++++++++++++++++++ + src/arm/code-stubs-arm.cc | 42 ++++++++++++++++++++++++++++++++++++++++-- + src/factory.cc | 8 ++++++++ + src/ia32/code-stubs-ia32.cc | 40 ++++++++++++++++++++++++++++++++++++++++ + src/isolate.h | 8 ++++++++ + src/objects-inl.h | 15 +++++++++++++++ + src/objects.h | 10 +++++++++- + src/runtime.cc | 23 +++++++++++++++++++++++ + src/runtime.h | 1 + + src/top.cc | 5 +++++ + src/x64/code-stubs-x64.cc | 37 +++++++++++++++++++++++++++++++++++++ + 12 files changed, 218 insertions(+), 3 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 8891dab..d5d6972 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2365,6 +2365,12 @@ class V8EXPORT ObjectTemplate : public Template { + bool HasExternalResource(); + void SetHasExternalResource(bool value); + ++ /** ++ * Mark object instances of the template as using the user object ++ * comparison callback. ++ */ ++ void MarkAsUseUserObjectComparison(); ++ + private: + ObjectTemplate(); + static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor); +@@ -2565,6 +2571,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target, + AccessType type, + Local<Value> data); + ++// --- U s e r O b j e c t C o m p a r i s o n C a l l b a c k --- ++typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs, ++ Local<Object> rhs); ++ + // --- G a r b a g e C o l l e c t i o n C a l l b a c k s + + /** +@@ -2815,6 +2825,9 @@ class V8EXPORT V8 { + /** Callback function for reporting failed access checks.*/ + static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); + ++ /** Callback for user object comparisons */ ++ static void SetUserObjectComparisonCallbackFunction(UserObjectComparisonCallback); ++ + /** + * Enables the host application to receive a notification before a + * garbage collection. Allocations are not allowed in the +diff --git a/src/api.cc b/src/api.cc +index ff74efb..2436031 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1321,6 +1321,16 @@ void ObjectTemplate::SetHasExternalResource(bool value) + } + } + ++void ObjectTemplate::MarkAsUseUserObjectComparison() ++{ ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUseUserObjectComparison()")) { ++ return; ++ } ++ ENTER_V8(isolate); ++ EnsureConstructor(this); ++ Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1)); ++} + + // --- S c r i p t D a t a --- + +@@ -4632,6 +4642,15 @@ void V8::SetFailedAccessCheckCallbackFunction( + isolate->SetFailedAccessCheckCallback(callback); + } + ++void V8::SetUserObjectComparisonCallbackFunction( ++ UserObjectComparisonCallback callback) { ++ i::Isolate* isolate = i::Isolate::Current(); ++ if (IsDeadCheck(isolate, "v8::V8::SetUserObjectComparisonCallbackFunction()")) { ++ return; ++ } ++ isolate->SetUserObjectComparisonCallback(callback); ++} ++ + void V8::AddObjectGroup(Persistent<Value>* objects, + size_t length, + RetainedObjectInfo* info) { +diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc +index a2626bf..749c9be 100644 +--- a/src/arm/code-stubs-arm.cc ++++ b/src/arm/code-stubs-arm.cc +@@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) { + // NOTICE! This code is only reached after a smi-fast-case check, so + // it is certain that at least one operand isn't a smi. + ++ { ++ Label not_user_equal, user_equal; ++ __ and_(r2, r1, Operand(r0)); ++ __ tst(r2, Operand(kSmiTagMask)); ++ __ b(eq, ¬_user_equal); ++ ++ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE); ++ __ b(ne, ¬_user_equal); ++ ++ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE); ++ __ b(ne, ¬_user_equal); ++ ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &user_equal); ++ ++ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset)); ++ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(ne, ¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ Push(r0, r1); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ + // Handle the case where the objects are identical. Either returns the answer + // or goes to slow. Only falls through if the objects were not identical. + EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); +@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + __ tst(r2, Operand(kSmiTagMask)); + __ b(eq, &miss); + +- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); ++ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE); + __ b(ne, &miss); +- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &miss); ++ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE); + __ b(ne, &miss); ++ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset)); ++ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); ++ __ b(eq, &miss); + + ASSERT(GetCondition() == eq); + __ sub(r0, r0, Operand(r1)); +diff --git a/src/factory.cc b/src/factory.cc +index d530a75..6f8c7de 100644 +--- a/src/factory.cc ++++ b/src/factory.cc +@@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction( + + int internal_field_count = 0; + bool has_external_resource = false; ++ bool use_user_object_comparison = false; + + if (!obj->instance_template()->IsUndefined()) { + Handle<ObjectTemplateInfo> instance_template = +@@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction( + Smi::cast(instance_template->internal_field_count())->value(); + has_external_resource = + !instance_template->has_external_resource()->IsUndefined(); ++ use_user_object_comparison = ++ !instance_template->use_user_object_comparison()->IsUndefined(); + } + + int instance_size = kPointerSize * internal_field_count; +@@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction( + map->set_has_external_resource(true); + } + ++ // Mark as using user object comparison if needed ++ if (use_user_object_comparison) { ++ map->set_use_user_object_comparison(true); ++ } ++ + // Mark as undetectable if needed. + if (obj->undetectable()) { + map->set_is_undetectable(); +diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc +index afa599e..0964ab9 100644 +--- a/src/ia32/code-stubs-ia32.cc ++++ b/src/ia32/code-stubs-ia32.cc +@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) { + __ Assert(not_zero, "Unexpected smi operands."); + } + ++ { ++ NearLabel not_user_equal, user_equal; ++ __ test(eax, Immediate(kSmiTagMask)); ++ __ j(zero, ¬_user_equal); ++ __ test(edx, Immediate(kSmiTagMask)); ++ __ j(zero, ¬_user_equal); ++ ++ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ test_b(FieldOperand(ebx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &user_equal); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &user_equal); ++ ++ __ jmp(¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ pop(ebx); // Return address. ++ __ push(eax); ++ __ push(edx); ++ __ push(ebx); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ ++ + // NOTICE! This code is only reached after a smi-fast-case check, so + // it is certain that at least one operand isn't a smi. + +@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + + __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); + __ j(not_equal, &miss, not_taken); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &miss); + __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); + __ j(not_equal, &miss, not_taken); ++ __ test_b(FieldOperand(ecx, Map::kBitField3Offset), ++ 1 << Map::kUseUserObjectComparison); ++ __ j(not_zero, &miss); + + ASSERT(GetCondition() == equal); + __ sub(eax, Operand(edx)); +diff --git a/src/isolate.h b/src/isolate.h +index 35ffcb4..8130397 100644 +--- a/src/isolate.h ++++ b/src/isolate.h +@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED { + // Call back function to report unsafe JS accesses. + v8::FailedAccessCheckCallback failed_access_check_callback_; + ++ // Call back function for user object comparisons ++ v8::UserObjectComparisonCallback user_object_comparison_callback_; ++ + private: + void InitializeInternal(); + +@@ -699,6 +702,11 @@ class Isolate { + void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback); + void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); + ++ void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback); ++ inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() { ++ return thread_local_top()->user_object_comparison_callback_; ++ } ++ + // Exception throwing support. The caller should use the result + // of Throw() as its return value. + Failure* Throw(Object* exception, MessageLocation* location = NULL); +diff --git a/src/objects-inl.h b/src/objects-inl.h +index 1c7f83e..1765441 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -2552,6 +2552,19 @@ bool Map::has_external_resource() + } + + ++void Map::set_use_user_object_comparison(bool value) { ++ if (value) { ++ set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison)); ++ } else { ++ set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison)); ++ } ++} ++ ++bool Map::use_user_object_comparison() { ++ return ((1 << kUseUserObjectComparison) & bit_field3()) != 0; ++} ++ ++ + void Map::set_named_interceptor_is_fallback(bool value) + { + if (value) { +@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, + kInternalFieldCountOffset) + ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, + kHasExternalResourceOffset) ++ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object, ++ kUseUserObjectComparisonOffset) + + ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) + ACCESSORS(SignatureInfo, args, Object, kArgsOffset) +diff --git a/src/objects.h b/src/objects.h +index edbc47a..e75e9f1 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -3724,6 +3724,11 @@ class Map: public HeapObject { + inline void set_has_external_resource(bool value); + inline bool has_external_resource(); + ++ ++ // Tells whether the user object comparison callback should be used for ++ // comparisons involving this object ++ inline void set_use_user_object_comparison(bool value); ++ inline bool use_user_object_comparison(); + + // Whether the named interceptor is a fallback interceptor or not + inline void set_named_interceptor_is_fallback(bool value); +@@ -3922,6 +3927,7 @@ class Map: public HeapObject { + // Bit positions for bit field 3 + static const int kNamedInterceptorIsFallback = 0; + static const int kHasExternalResource = 1; ++ static const int kUseUserObjectComparison = 2; + + // Layout of the default cache. It holds alternating name and code objects. + static const int kCodeCacheEntrySize = 2; +@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo { + DECL_ACCESSORS(constructor, Object) + DECL_ACCESSORS(internal_field_count, Object) + DECL_ACCESSORS(has_external_resource, Object) ++ DECL_ACCESSORS(use_user_object_comparison, Object) + + static inline ObjectTemplateInfo* cast(Object* obj); + +@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo { + static const int kInternalFieldCountOffset = + kConstructorOffset + kPointerSize; + static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; +- static const int kSize = kHasExternalResourceOffset + kPointerSize; ++ static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize; ++ static const int kSize = kUseUserObjectComparisonOffset + kPointerSize; + }; + + +diff --git a/src/runtime.cc b/src/runtime.cc +index 827d954..d552ddb 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { + } + + ++RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) { ++ NoHandleAllocation ha; ++ ASSERT(args.length() == 2); ++ ++ CONVERT_CHECKED(JSObject, lhs, args[1]); ++ CONVERT_CHECKED(JSObject, rhs, args[0]); ++ ++ bool result; ++ ++ v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback(); ++ if (callback) { ++ HandleScope scope(isolate); ++ Handle<JSObject> lhs_handle(lhs); ++ Handle<JSObject> rhs_handle(rhs); ++ result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle)); ++ } else { ++ result = (lhs == rhs); ++ } ++ ++ return Smi::FromInt(result?0:1); ++} ++ ++ + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { + NoHandleAllocation ha; + ASSERT(args.length() == 3); +diff --git a/src/runtime.h b/src/runtime.h +index 5e97173..0d754f9 100644 +--- a/src/runtime.h ++++ b/src/runtime.h +@@ -146,6 +146,7 @@ namespace internal { + /* Comparisons */ \ + F(NumberEquals, 2, 1) \ + F(StringEquals, 2, 1) \ ++ F(UserObjectEquals, 2, 1) \ + \ + F(NumberCompare, 3, 1) \ + F(SmiLexicographicCompare, 2, 1) \ +diff --git a/src/top.cc b/src/top.cc +index e078ee9..c345383 100644 +--- a/src/top.cc ++++ b/src/top.cc +@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() { + thread_id_ = ThreadId::Invalid(); + external_caught_exception_ = false; + failed_access_check_callback_ = NULL; ++ user_object_comparison_callback_ = NULL; + save_context_ = NULL; + catcher_ = NULL; + } +@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback( + thread_local_top()->failed_access_check_callback_ = callback; + } + ++void Isolate::SetUserObjectComparisonCallback( ++ v8::UserObjectComparisonCallback callback) { ++ thread_local_top()->user_object_comparison_callback_ = callback; ++} + + void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { + if (!thread_local_top()->failed_access_check_callback_) return; +diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc +index d923494..10b9b56 100644 +--- a/src/x64/code-stubs-x64.cc ++++ b/src/x64/code-stubs-x64.cc +@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) { + __ bind(&ok); + } + ++ { ++ NearLabel not_user_equal, user_equal; ++ __ JumpIfSmi(rax, ¬_user_equal); ++ __ JumpIfSmi(rdx, ¬_user_equal); ++ ++ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); ++ __ j(not_equal, ¬_user_equal); ++ ++ __ testb(FieldOperand(rbx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &user_equal); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &user_equal); ++ ++ __ jmp(¬_user_equal); ++ ++ __ bind(&user_equal); ++ ++ __ pop(rbx); // Return address. ++ __ push(rax); ++ __ push(rdx); ++ __ push(rbx); ++ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1); ++ ++ __ bind(¬_user_equal); ++ } ++ + // The compare stub returns a positive, negative, or zero 64-bit integer + // value in rax, corresponding to result of comparing the two inputs. + // NOTICE! This code is only reached after a smi-fast-case check, so +@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { + + __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); + __ j(not_equal, &miss, not_taken); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &miss); + __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); + __ j(not_equal, &miss, not_taken); ++ __ testb(FieldOperand(rcx, Map::kBitField3Offset), ++ Immediate(1 << Map::kUseUserObjectComparison)); ++ __ j(not_zero, &miss); + + ASSERT(GetCondition() == equal); + __ subq(rax, rdx); +-- +1.7.2.3 + diff --git a/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch new file mode 100644 index 0000000000..d197ac9e48 --- /dev/null +++ b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch @@ -0,0 +1,286 @@ +From 4183b973ed3bd603784c798dfa63ba48f6b68003 Mon Sep 17 00:00:00 2001 +From: ager@chromium.org <ager@chromium.org> +Date: Wed, 4 May 2011 13:03:08 +0000 +Subject: [PATCH 09/13] Add CallAsFunction method to the Object class in the API + +Patch by Peter Varga. + +BUG=v8:1336 +TEST=cctest/test-api/CallAsFunction + +Review URL: http://codereview.chromium.org/6883045 + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 +--- + include/v8.h | 8 +++ + src/api.cc | 31 +++++++++++ + src/execution.cc | 24 ++++++++ + src/execution.h | 2 + + test/cctest/test-api.cc | 135 ++++++++++++++++++++++++++++++++++------------- + 5 files changed, 163 insertions(+), 37 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index d5d6972..8a8e1cd 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1757,6 +1757,14 @@ class Object : public Value { + V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType(); + V8EXPORT int GetIndexedPropertiesExternalArrayDataLength(); + ++ /** ++ * Call an Object as a function if a callback is set by the ++ * ObjectTemplate::SetCallAsFunctionHandler method. ++ */ ++ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv, ++ int argc, ++ Handle<Value> argv[]); ++ + V8EXPORT static Local<Object> New(); + static inline Object* Cast(Value* obj); + private: +diff --git a/src/api.cc b/src/api.cc +index 2436031..e412e51 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3259,6 +3259,37 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() { + } + + ++Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, ++ v8::Handle<v8::Value> argv[]) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ON_BAILOUT(isolate, "v8::Object::CallAsFunction()", ++ return Local<v8::Value>()); ++ LOG_API(isolate, "Object::CallAsFunction"); ++ ENTER_V8(isolate); ++ HandleScope scope; ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); ++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); ++ i::Object*** args = reinterpret_cast<i::Object***>(argv); ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>(); ++ if (obj->IsJSFunction()) { ++ fun = i::Handle<i::JSFunction>::cast(obj); ++ } else { ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> delegate = ++ i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); ++ fun = i::Handle<i::JSFunction>::cast(delegate); ++ recv_obj = obj; ++ } ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); ++ return scope.Close(Utils::ToLocal(returned)); ++} ++ ++ + Local<v8::Object> Function::NewInstance() const { + return NewInstance(0, NULL); + } +diff --git a/src/execution.cc b/src/execution.cc +index 1632076..894d741 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -254,6 +254,30 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) { + } + + ++Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object, ++ bool* has_pending_exception) { ++ ASSERT(!object->IsJSFunction()); ++ Isolate* isolate = Isolate::Current(); ++ ++ // Objects created through the API can have an instance-call handler ++ // that should be used when calling the object as a function. ++ if (object->IsHeapObject() && ++ HeapObject::cast(*object)->map()->has_instance_call_handler()) { ++ return Handle<JSFunction>( ++ isolate->global_context()->call_as_function_delegate()); ++ } ++ ++ // If the Object doesn't have an instance-call handler we should ++ // throw a non-callable exception. ++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError( ++ "called_non_callable", i::HandleVector<i::Object>(&object, 1)); ++ isolate->Throw(*error_obj); ++ *has_pending_exception = true; ++ ++ return isolate->factory()->undefined_value(); ++} ++ ++ + Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { + ASSERT(!object->IsJSFunction()); + Isolate* isolate = Isolate::Current(); +diff --git a/src/execution.h b/src/execution.h +index a476eb4..0a0be51 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -144,6 +144,8 @@ class Execution : public AllStatic { + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as functions. + static Handle<Object> GetFunctionDelegate(Handle<Object> object); ++ static Handle<Object> TryGetFunctionDelegate(Handle<Object> object, ++ bool* has_pending_exception); + + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as constructors. +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index d7621d1..693d51e 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -6962,50 +6962,111 @@ THREADED_TEST(CallAsFunction) { + v8::HandleScope scope; + LocalContext context; + +- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); +- Local<ObjectTemplate> instance_template = t->InstanceTemplate(); +- instance_template->SetCallAsFunctionHandler(call_as_function); +- Local<v8::Object> instance = t->GetFunction()->NewInstance(); +- context->Global()->Set(v8_str("obj"), instance); +- v8::TryCatch try_catch; +- Local<Value> value; +- CHECK(!try_catch.HasCaught()); ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ instance_template->SetCallAsFunctionHandler(call_as_function); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); + +- value = CompileRun("obj(42)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(42, value->Int32Value()); ++ value = CompileRun("obj(42)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(42, value->Int32Value()); + +- value = CompileRun("(function(o){return o(49)})(obj)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(49, value->Int32Value()); ++ value = CompileRun("(function(o){return o(49)})(obj)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(49, value->Int32Value()); + +- // test special case of call as function +- value = CompileRun("[obj]['0'](45)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(45, value->Int32Value()); ++ // test special case of call as function ++ value = CompileRun("[obj]['0'](45)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(45, value->Int32Value()); + +- value = CompileRun("obj.call = Function.prototype.call;" +- "obj.call(null, 87)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(87, value->Int32Value()); ++ value = CompileRun("obj.call = Function.prototype.call;" ++ "obj.call(null, 87)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(87, value->Int32Value()); + +- // Regression tests for bug #1116356: Calling call through call/apply +- // must work for non-function receivers. +- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; +- value = CompileRun(apply_99); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(99, value->Int32Value()); ++ // Regression tests for bug #1116356: Calling call through call/apply ++ // must work for non-function receivers. ++ const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; ++ value = CompileRun(apply_99); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(99, value->Int32Value()); + +- const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; +- value = CompileRun(call_17); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(17, value->Int32Value()); ++ const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; ++ value = CompileRun(call_17); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(17, value->Int32Value()); + +- // Check that the call-as-function handler can be called through +- // new. +- value = CompileRun("new obj(43)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(-43, value->Int32Value()); ++ // Check that the call-as-function handler can be called through ++ // new. ++ value = CompileRun("new obj(43)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(-43, value->Int32Value()); ++ ++ // Check that the call-as-function handler can be called through ++ // the API. ++ v8::Handle<Value> args[] = { v8_num(28) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(28, value->Int32Value()); ++ } ++ ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj2"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Call an object without call-as-function handler through the JS ++ value = CompileRun("obj2(28)"); ++ CHECK(value.IsEmpty()); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ(*exception_value1, ++ "TypeError: Property 'obj2' of object " ++ "#<Object> is not a function"); ++ try_catch.Reset(); ++ ++ // Call an object without call-as-function handler through the API ++ value = CompileRun("obj2(28)"); ++ v8::Handle<Value> args[] = { v8_num(28) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(value.IsEmpty()); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function"); ++ try_catch.Reset(); ++ } ++ ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ instance_template->SetCallAsFunctionHandler(ThrowValue); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj3"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Catch the exception which is thrown by call-as-function handler ++ value = CompileRun("obj3(22)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ(*exception_value1, "22"); ++ try_catch.Reset(); ++ ++ v8::Handle<Value> args[] = { v8_num(23) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ(*exception_value2, "23"); ++ try_catch.Reset(); ++ } + } + + +-- +1.7.2.3 + diff --git a/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch new file mode 100644 index 0000000000..cb4dd186d6 --- /dev/null +++ b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch @@ -0,0 +1,397 @@ +From 3d6d4249878f7960eac4c9c94e0f2529f9a58c4a Mon Sep 17 00:00:00 2001 +From: ager@chromium.org <ager@chromium.org> +Date: Fri, 6 May 2011 11:07:52 +0000 +Subject: [PATCH 10/13] Implement CallAsConstructor method for Object in the API + +Patch by Peter Varga. + +BUG=v8:1348 +TEST=cctest/test-api/ConstructorForObject + +Review URL: http://codereview.chromium.org/6902108 + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7803 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 +--- + include/v8.h | 8 ++ + src/api.cc | 41 +++++++++- + src/execution.cc | 28 +++++++ + src/execution.h | 2 + + test/cctest/test-api.cc | 205 +++++++++++++++++++++++++++++++++++++++++++++-- + 5 files changed, 276 insertions(+), 8 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 8a8e1cd..84462b5 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1765,6 +1765,14 @@ class Object : public Value { + int argc, + Handle<Value> argv[]); + ++ /** ++ * Call an Object as a consturctor if a callback is set by the ++ * ObjectTemplate::SetCallAsFunctionHandler method. ++ * Note: This method behaves like the Function::NewInstance method. ++ */ ++ V8EXPORT Local<Value> CallAsConstructor(int argc, ++ Handle<Value> argv[]); ++ + V8EXPORT static Local<Object> New(); + static inline Object* Cast(Value* obj); + private: +diff --git a/src/api.cc b/src/api.cc +index e412e51..1a585d6 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3266,7 +3266,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, + return Local<v8::Value>()); + LOG_API(isolate, "Object::CallAsFunction"); + ENTER_V8(isolate); +- HandleScope scope; ++ i::HandleScope scope(isolate); + i::Handle<i::JSObject> obj = Utils::OpenHandle(this); + i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); + STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); +@@ -3286,7 +3286,44 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, + i::Handle<i::Object> returned = + i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); + EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); +- return scope.Close(Utils::ToLocal(returned)); ++ return Utils::ToLocal(scope.CloseAndEscape(returned)); ++} ++ ++ ++Local<v8::Value> Object::CallAsConstructor(int argc, ++ v8::Handle<v8::Value> argv[]) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()", ++ return Local<v8::Object>()); ++ LOG_API(isolate, "Object::CallAsConstructor"); ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); ++ i::Object*** args = reinterpret_cast<i::Object***>(argv); ++ if (obj->IsJSFunction()) { ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj); ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::New(fun, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ return Utils::ToLocal(scope.CloseAndEscape( ++ i::Handle<i::JSObject>::cast(returned))); ++ } ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> delegate = ++ i::Execution::TryGetConstructorDelegate(obj, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ if (!delegate->IsUndefined()) { ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate); ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::Call(fun, obj, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ ASSERT(!delegate->IsUndefined()); ++ return Utils::ToLocal(scope.CloseAndEscape(returned)); ++ } ++ return Local<v8::Object>(); + } + + +diff --git a/src/execution.cc b/src/execution.cc +index 894d741..afb352c 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -297,6 +297,34 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { + } + + ++Handle<Object> Execution::TryGetConstructorDelegate( ++ Handle<Object> object, ++ bool* has_pending_exception) { ++ ASSERT(!object->IsJSFunction()); ++ Isolate* isolate = Isolate::Current(); ++ ++ // If you return a function from here, it will be called when an ++ // attempt is made to call the given object as a constructor. ++ ++ // Objects created through the API can have an instance-call handler ++ // that should be used when calling the object as a function. ++ if (object->IsHeapObject() && ++ HeapObject::cast(*object)->map()->has_instance_call_handler()) { ++ return Handle<JSFunction>( ++ isolate->global_context()->call_as_constructor_delegate()); ++ } ++ ++ // If the Object doesn't have an instance-call handler we should ++ // throw a non-callable exception. ++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError( ++ "called_non_callable", i::HandleVector<i::Object>(&object, 1)); ++ isolate->Throw(*error_obj); ++ *has_pending_exception = true; ++ ++ return isolate->factory()->undefined_value(); ++} ++ ++ + bool StackGuard::IsStackOverflow() { + ExecutionAccess access(isolate_); + return (thread_local_.jslimit_ != kInterruptLimit && +diff --git a/src/execution.h b/src/execution.h +index 0a0be51..ec2a195 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -150,6 +150,8 @@ class Execution : public AllStatic { + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as constructors. + static Handle<Object> GetConstructorDelegate(Handle<Object> object); ++ static Handle<Object> TryGetConstructorDelegate(Handle<Object> object, ++ bool* has_pending_exception); + }; + + +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index 693d51e..1334f63 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -6746,6 +6746,200 @@ THREADED_TEST(Constructor) { + CHECK(value->BooleanValue()); + } + ++ ++static Handle<Value> ConstructorCallback(const Arguments& args) { ++ ApiTestFuzzer::Fuzz(); ++ Local<Object> This; ++ ++ if (args.IsConstructCall()) { ++ Local<Object> Holder = args.Holder(); ++ This = Object::New(); ++ Local<Value> proto = Holder->GetPrototype(); ++ if (proto->IsObject()) { ++ This->SetPrototype(proto); ++ } ++ } else { ++ This = args.This(); ++ } ++ ++ This->Set(v8_str("a"), args[0]); ++ return This; ++} ++ ++ ++static Handle<Value> FakeConstructorCallback(const Arguments& args) { ++ ApiTestFuzzer::Fuzz(); ++ return args[0]; ++} ++ ++ ++THREADED_TEST(ConstructorForObject) { ++ v8::HandleScope handle_scope; ++ LocalContext context; ++ ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(ConstructorCallback); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Call the Object's constructor with a 32-bit signed integer. ++ value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsInt32()); ++ CHECK_EQ(28, value->Int32Value()); ++ ++ Local<Value> args1[] = { v8_num(28) }; ++ Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); ++ CHECK(value_obj1->IsObject()); ++ Local<Object> object1 = Local<Object>::Cast(value_obj1); ++ value = object1->Get(v8_str("a")); ++ CHECK(value->IsInt32()); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(28, value->Int32Value()); ++ ++ // Call the Object's constructor with a String. ++ value = CompileRun( ++ "(function() { var o = new obj('tipli'); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsString()); ++ String::AsciiValue string_value1(value->ToString()); ++ CHECK_EQ("tipli", *string_value1); ++ ++ Local<Value> args2[] = { v8_str("tipli") }; ++ Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); ++ CHECK(value_obj2->IsObject()); ++ Local<Object> object2 = Local<Object>::Cast(value_obj2); ++ value = object2->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsString()); ++ String::AsciiValue string_value2(value->ToString()); ++ CHECK_EQ("tipli", *string_value2); ++ ++ // Call the Object's constructor with a Boolean. ++ value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsBoolean()); ++ CHECK_EQ(true, value->BooleanValue()); ++ ++ Handle<Value> args3[] = { v8::Boolean::New(true) }; ++ Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); ++ CHECK(value_obj3->IsObject()); ++ Local<Object> object3 = Local<Object>::Cast(value_obj3); ++ value = object3->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsBoolean()); ++ CHECK_EQ(true, value->BooleanValue()); ++ ++ // Call the Object's constructor with undefined. ++ Handle<Value> args4[] = { v8::Undefined() }; ++ Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); ++ CHECK(value_obj4->IsObject()); ++ Local<Object> object4 = Local<Object>::Cast(value_obj4); ++ value = object4->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsUndefined()); ++ ++ // Call the Object's constructor with null. ++ Handle<Value> args5[] = { v8::Null() }; ++ Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); ++ CHECK(value_obj5->IsObject()); ++ Local<Object> object5 = Local<Object>::Cast(value_obj5); ++ value = object5->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsNull()); ++ } ++ ++ // Check exception handling when there is no constructor set for the Object. ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj2"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ value = CompileRun("new obj2(28)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ("TypeError: object is not a function", *exception_value1); ++ try_catch.Reset(); ++ ++ Local<Value> args[] = { v8_num(29) }; ++ value = instance->CallAsConstructor(1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); ++ try_catch.Reset(); ++ } ++ ++ // Check the case when constructor throws exception. ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(ThrowValue); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj3"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ value = CompileRun("new obj3(22)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ("22", *exception_value1); ++ try_catch.Reset(); ++ ++ Local<Value> args[] = { v8_num(23) }; ++ value = instance->CallAsConstructor(1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ("23", *exception_value2); ++ try_catch.Reset(); ++ } ++ ++ // Check whether constructor returns with an object or non-object. ++ { Local<FunctionTemplate> function_template = ++ FunctionTemplate::New(FakeConstructorCallback); ++ Local<Function> function = function_template->GetFunction(); ++ Local<Object> instance1 = function; ++ context->Global()->Set(v8_str("obj4"), instance1); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ CHECK(instance1->IsObject()); ++ CHECK(instance1->IsFunction()); ++ ++ value = CompileRun("new obj4(28)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsObject()); ++ ++ Local<Value> args1[] = { v8_num(28) }; ++ value = instance1->CallAsConstructor(1, args1); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsObject()); ++ ++ Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); ++ Local<Object> instance2 = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj5"), instance2); ++ CHECK(!try_catch.HasCaught()); ++ ++ CHECK(instance2->IsObject()); ++ CHECK(!instance2->IsFunction()); ++ ++ value = CompileRun("new obj5(28)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(!value->IsObject()); ++ ++ Local<Value> args2[] = { v8_num(28) }; ++ value = instance2->CallAsConstructor(1, args2); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(!value->IsObject()); ++ } ++} ++ ++ + THREADED_TEST(FunctionDescriptorException) { + v8::HandleScope handle_scope; + LocalContext context; +@@ -7028,9 +7222,8 @@ THREADED_TEST(CallAsFunction) { + CHECK(value.IsEmpty()); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value1(try_catch.Exception()); +- CHECK_EQ(*exception_value1, +- "TypeError: Property 'obj2' of object " +- "#<Object> is not a function"); ++ CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", ++ *exception_value1); + try_catch.Reset(); + + // Call an object without call-as-function handler through the API +@@ -7040,7 +7233,7 @@ THREADED_TEST(CallAsFunction) { + CHECK(value.IsEmpty()); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value2(try_catch.Exception()); +- CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function"); ++ CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); + try_catch.Reset(); + } + +@@ -7057,14 +7250,14 @@ THREADED_TEST(CallAsFunction) { + value = CompileRun("obj3(22)"); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value1(try_catch.Exception()); +- CHECK_EQ(*exception_value1, "22"); ++ CHECK_EQ("22", *exception_value1); + try_catch.Reset(); + + v8::Handle<Value> args[] = { v8_num(23) }; + value = instance->CallAsFunction(instance, 1, args); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value2(try_catch.Exception()); +- CHECK_EQ(*exception_value2, "23"); ++ CHECK_EQ("23", *exception_value2); + try_catch.Reset(); + } + } +-- +1.7.2.3 + diff --git a/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch new file mode 100644 index 0000000000..9c0e68352f --- /dev/null +++ b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch @@ -0,0 +1,63 @@ +From f22d0312faeb93ced8747d9aae8c6d77e11b4aba Mon Sep 17 00:00:00 2001 +From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com> +Date: Tue, 7 Dec 2010 11:56:42 +0100 +Subject: [PATCH 11/13] QtScript/V8: Add new v8 api to check if a value is an error. + +New function v8::Value::IsError was created. + +This API is experimental and added only for the purposes of our +research. +--- + include/v8.h | 5 +++++ + src/api.cc | 6 ++++++ + src/heap.h | 1 + + 3 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 84462b5..08b0ec2 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -937,6 +937,11 @@ class Value : public Data { + */ + V8EXPORT bool IsRegExp() const; + ++ /** ++ * Returns true if this value is an Error. ++ */ ++ V8EXPORT bool IsError() const; ++ + V8EXPORT Local<Boolean> ToBoolean() const; + V8EXPORT Local<Number> ToNumber() const; + V8EXPORT Local<String> ToString() const; +diff --git a/src/api.cc b/src/api.cc +index 1a585d6..bd435eb 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const { + return obj->IsJSRegExp(); + } + ++bool Value::IsError() const { ++ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsError()")) return false; ++ i::Handle<i::Object> obj = Utils::OpenHandle(this); ++ return obj->HasSpecificClassOf(HEAP->Error_symbol()); ++} ++ + + Local<String> Value::ToString() const { + i::Handle<i::Object> obj = Utils::OpenHandle(this); +diff --git a/src/heap.h b/src/heap.h +index 8cbf378..db90bb9 100644 +--- a/src/heap.h ++++ b/src/heap.h +@@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_(); + V(string_symbol, "string") \ + V(String_symbol, "String") \ + V(Date_symbol, "Date") \ ++ V(Error_symbol, "Error") \ + V(this_symbol, "this") \ + V(to_string_symbol, "toString") \ + V(char_at_symbol, "CharAt") \ +-- +1.7.2.3 + diff --git a/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch b/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch new file mode 100644 index 0000000000..77589c8af3 --- /dev/null +++ b/src/v8/0012-Add-IsCallable-method-for-Object-in-the-API.patch @@ -0,0 +1,116 @@ +From 472c04c9e7a64e8734c76d2cf97a7cc5b773b788 Mon Sep 17 00:00:00 2001 +From: ager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00> +Date: Mon, 9 May 2011 15:24:48 +0000 +Subject: [PATCH 12/13] Add IsCallable method for Object in the API + +Patch by Peter Varga. + +BUG=none +TEST=cctest/test-api/CallableObject + +Review URL: http://codereview.chromium.org/6964005 + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7828 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 +--- + include/v8.h | 7 +++++++ + src/api.cc | 11 +++++++++++ + test/cctest/test-api.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 61 insertions(+), 0 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 08b0ec2..4194d4a 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1763,6 +1763,13 @@ class Object : public Value { + V8EXPORT int GetIndexedPropertiesExternalArrayDataLength(); + + /** ++ * Checks whether a callback is set by the ++ * ObjectTemplate::SetCallAsFunctionHandler method. ++ * When an Object is callable this method returns true. ++ */ ++ V8EXPORT bool IsCallable(); ++ ++ /** + * Call an Object as a function if a callback is set by the + * ObjectTemplate::SetCallAsFunctionHandler method. + */ +diff --git a/src/api.cc b/src/api.cc +index bd435eb..a5a637f 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3265,6 +3265,17 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() { + } + + ++bool v8::Object::IsCallable() { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ON_BAILOUT(isolate, "v8::Object::IsCallable()", return false); ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ if (obj->IsJSFunction()) return true; ++ return i::Execution::GetFunctionDelegate(obj)->IsJSFunction(); ++} ++ ++ + Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, + v8::Handle<v8::Value> argv[]) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index 1334f63..45db5a1 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -7263,6 +7263,49 @@ THREADED_TEST(CallAsFunction) { + } + + ++// Check whether a non-function object is callable. ++THREADED_TEST(CallableObject) { ++ v8::HandleScope scope; ++ LocalContext context; ++ ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(call_as_function); ++ Local<Object> instance = instance_template->NewInstance(); ++ v8::TryCatch try_catch; ++ ++ CHECK(instance->IsCallable()); ++ CHECK(!try_catch.HasCaught()); ++ } ++ ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ Local<Object> instance = instance_template->NewInstance(); ++ v8::TryCatch try_catch; ++ ++ CHECK(!instance->IsCallable()); ++ CHECK(!try_catch.HasCaught()); ++ } ++ ++ { Local<FunctionTemplate> function_template = ++ FunctionTemplate::New(call_as_function); ++ Local<Function> function = function_template->GetFunction(); ++ Local<Object> instance = function; ++ v8::TryCatch try_catch; ++ ++ CHECK(instance->IsCallable()); ++ CHECK(!try_catch.HasCaught()); ++ } ++ ++ { Local<FunctionTemplate> function_template = FunctionTemplate::New(); ++ Local<Function> function = function_template->GetFunction(); ++ Local<Object> instance = function; ++ v8::TryCatch try_catch; ++ ++ CHECK(instance->IsCallable()); ++ CHECK(!try_catch.HasCaught()); ++ } ++} ++ ++ + static int CountHandles() { + return v8::HandleScope::NumberOfHandles(); + } +-- +1.7.2.3 + diff --git a/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch b/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch new file mode 100644 index 0000000000..6bad561273 --- /dev/null +++ b/src/v8/0013-Remove-execute-flag-from-v8-debug.h.patch @@ -0,0 +1,15 @@ +From dc2cad4f8fc88c52fcea09b8d0262d35cd32dc44 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Thu, 25 Aug 2011 11:09:58 +1000 +Subject: [PATCH 13/13] Remove execute flag from v8-debug.h + +--- + 0 files changed, 0 insertions(+), 0 deletions(-) + mode change 100755 => 100644 include/v8-debug.h + +diff --git a/include/v8-debug.h b/include/v8-debug.h +old mode 100755 +new mode 100644 +-- +1.7.2.3 + diff --git a/src/v8/README b/src/v8/README new file mode 100644 index 0000000000..2dc39705aa --- /dev/null +++ b/src/v8/README @@ -0,0 +1 @@ +These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2 diff --git a/src/v8/v8.pri b/src/v8/v8.pri new file mode 100644 index 0000000000..4d55bbfd5a --- /dev/null +++ b/src/v8/v8.pri @@ -0,0 +1,260 @@ +equals(QT_ARCH, x86_64)|contains(CONFIG, x86_64):CONFIG += arch_x86_64 +else:equals(QT_ARCH, "i386"):CONFIG += arch_i386 +else:equals(QT_ARCH, "arm"):CONFIG += arch_arm +else:equals(QMAKE_HOST.arch, armv7l):CONFIG += arch_arm +else:equals(QMAKE_HOST.arch, x86_64):CONFIG += arch_x86_64 +else:equals(QMAKE_HOST.arch, x86):CONFIG += arch_i386 +else:equals(QMAKE_HOST.arch, i386):CONFIG += arch_i386 +else:equals(QMAKE_HOST.arch, i686):CONFIG += arch_i386 +else:error("Couldn't detect supported architecture ($$QMAKE_HOST.arch/$$QT_ARCH). Currently supported architectures are: x64, x86 and arm") + +include($$PWD/v8base.pri) + +V8_GENERATED_SOURCES_DIR = generated + +!contains(QT_CONFIG, static): DEFINES += V8_SHARED BUILDING_V8_SHARED + +# this maybe removed in future +DEFINES += ENABLE_DEBUGGER_SUPPORT + +# this is needed by crankshaft ( http://code.google.com/p/v8/issues/detail?id=1271 ) +DEFINES += ENABLE_VMSTATE_TRACKING ENABLE_LOGGING_AND_PROFILING + +CONFIG(debug, debug|release) { + DEFINES += DEBUG V8_ENABLE_CHECKS OBJECT_PRINT ENABLE_DISASSEMBLER +} else { + DEFINES += NDEBUG +} + +V8SRC = $$V8DIR/src + +INCLUDEPATH += \ + $$V8SRC + +SOURCES += \ + $$V8SRC/accessors.cc \ + $$V8SRC/allocation.cc \ + $$V8SRC/api.cc \ + $$V8SRC/assembler.cc \ + $$V8SRC/ast.cc \ + $$V8SRC/atomicops_internals_x86_gcc.cc \ + $$V8SRC/bignum.cc \ + $$V8SRC/bignum-dtoa.cc \ + $$V8SRC/bootstrapper.cc \ + $$V8SRC/builtins.cc \ + $$V8SRC/cached-powers.cc \ + $$V8SRC/checks.cc \ + $$V8SRC/circular-queue.cc \ + $$V8SRC/code-stubs.cc \ + $$V8SRC/codegen.cc \ + $$V8SRC/compilation-cache.cc \ + $$V8SRC/compiler.cc \ + $$V8SRC/contexts.cc \ + $$V8SRC/conversions.cc \ + $$V8SRC/counters.cc \ + $$V8SRC/cpu-profiler.cc \ + $$V8SRC/data-flow.cc \ + $$V8SRC/dateparser.cc \ + $$V8SRC/debug-agent.cc \ + $$V8SRC/debug.cc \ + $$V8SRC/deoptimizer.cc \ + $$V8SRC/disassembler.cc \ + $$V8SRC/diy-fp.cc \ + $$V8SRC/dtoa.cc \ + $$V8SRC/execution.cc \ + $$V8SRC/factory.cc \ + $$V8SRC/flags.cc \ + $$V8SRC/frame-element.cc \ + $$V8SRC/frames.cc \ + $$V8SRC/full-codegen.cc \ + $$V8SRC/func-name-inferrer.cc \ + $$V8SRC/gdb-jit.cc \ + $$V8SRC/global-handles.cc \ + $$V8SRC/fast-dtoa.cc \ + $$V8SRC/fixed-dtoa.cc \ + $$V8SRC/handles.cc \ + $$V8SRC/hashmap.cc \ + $$V8SRC/heap-profiler.cc \ + $$V8SRC/heap.cc \ + $$V8SRC/hydrogen.cc \ + $$V8SRC/hydrogen-instructions.cc \ + $$V8SRC/ic.cc \ + $$V8SRC/inspector.cc \ + $$V8SRC/interpreter-irregexp.cc \ + $$V8SRC/isolate.cc \ + $$V8SRC/jsregexp.cc \ + $$V8SRC/lithium-allocator.cc \ + $$V8SRC/lithium.cc \ + $$V8SRC/liveedit.cc \ + $$V8SRC/liveobjectlist.cc \ + $$V8SRC/log-utils.cc \ + $$V8SRC/log.cc \ + $$V8SRC/mark-compact.cc \ + $$V8SRC/messages.cc \ + $$V8SRC/objects.cc \ + $$V8SRC/objects-printer.cc \ + $$V8SRC/objects-visiting.cc \ + $$V8SRC/parser.cc \ + $$V8SRC/preparser.cc \ + $$V8SRC/preparse-data.cc \ + $$V8SRC/profile-generator.cc \ + $$V8SRC/property.cc \ + $$V8SRC/regexp-macro-assembler-irregexp.cc \ + $$V8SRC/regexp-macro-assembler.cc \ + $$V8SRC/regexp-stack.cc \ + $$V8SRC/rewriter.cc \ + $$V8SRC/runtime.cc \ + $$V8SRC/runtime-profiler.cc \ + $$V8SRC/safepoint-table.cc \ + $$V8SRC/scanner-base.cc \ + $$V8SRC/scanner.cc \ + $$V8SRC/scopeinfo.cc \ + $$V8SRC/scopes.cc \ + $$V8SRC/serialize.cc \ + $$V8SRC/snapshot-common.cc \ + $$V8SRC/spaces.cc \ + $$V8SRC/string-search.cc \ + $$V8SRC/string-stream.cc \ + $$V8SRC/strtod.cc \ + $$V8SRC/stub-cache.cc \ + $$V8SRC/token.cc \ + $$V8SRC/top.cc \ + $$V8SRC/type-info.cc \ + $$V8SRC/unicode.cc \ + $$V8SRC/utils.cc \ + $$V8SRC/v8-counters.cc \ + $$V8SRC/v8.cc \ + $$V8SRC/v8threads.cc \ + $$V8SRC/variables.cc \ + $$V8SRC/version.cc \ + $$V8SRC/zone.cc \ + $$V8SRC/extensions/gc-extension.cc \ + $$V8SRC/extensions/externalize-string-extension.cc + +SOURCES += \ + $$V8SRC/snapshot-empty.cc \ + +arch_arm { +DEFINES += V8_TARGET_ARCH_ARM +SOURCES += \ + $$V8SRC/arm/builtins-arm.cc \ + $$V8SRC/arm/code-stubs-arm.cc \ + $$V8SRC/arm/codegen-arm.cc \ + $$V8SRC/arm/constants-arm.cc \ + $$V8SRC/arm/cpu-arm.cc \ + $$V8SRC/arm/debug-arm.cc \ + $$V8SRC/arm/deoptimizer-arm.cc \ + $$V8SRC/arm/disasm-arm.cc \ + $$V8SRC/arm/frames-arm.cc \ + $$V8SRC/arm/full-codegen-arm.cc \ + $$V8SRC/arm/ic-arm.cc \ + $$V8SRC/arm/lithium-arm.cc \ + $$V8SRC/arm/lithium-codegen-arm.cc \ + $$V8SRC/arm/lithium-gap-resolver-arm.cc \ + $$V8SRC/arm/macro-assembler-arm.cc \ + $$V8SRC/arm/regexp-macro-assembler-arm.cc \ + $$V8SRC/arm/stub-cache-arm.cc \ + $$V8SRC/arm/assembler-arm.cc +} + +arch_i386 { +DEFINES += V8_TARGET_ARCH_IA32 +SOURCES += \ + $$V8SRC/ia32/assembler-ia32.cc \ + $$V8SRC/ia32/builtins-ia32.cc \ + $$V8SRC/ia32/code-stubs-ia32.cc \ + $$V8SRC/ia32/codegen-ia32.cc \ + $$V8SRC/ia32/cpu-ia32.cc \ + $$V8SRC/ia32/debug-ia32.cc \ + $$V8SRC/ia32/deoptimizer-ia32.cc \ + $$V8SRC/ia32/disasm-ia32.cc \ + $$V8SRC/ia32/frames-ia32.cc \ + $$V8SRC/ia32/full-codegen-ia32.cc \ + $$V8SRC/ia32/ic-ia32.cc \ + $$V8SRC/ia32/lithium-codegen-ia32.cc \ + $$V8SRC/ia32/lithium-gap-resolver-ia32.cc \ + $$V8SRC/ia32/lithium-ia32.cc \ + $$V8SRC/ia32/macro-assembler-ia32.cc \ + $$V8SRC/ia32/regexp-macro-assembler-ia32.cc \ + $$V8SRC/ia32/stub-cache-ia32.cc +} + +# FIXME Should we use QT_CONFIG instead? What about 32 bit Macs? +arch_x86_64 { +DEFINES += V8_TARGET_ARCH_X64 +SOURCES += \ + $$V8SRC/x64/assembler-x64.cc \ + $$V8SRC/x64/builtins-x64.cc \ + $$V8SRC/x64/code-stubs-x64.cc \ + $$V8SRC/x64/codegen-x64.cc \ + $$V8SRC/x64/cpu-x64.cc \ + $$V8SRC/x64/debug-x64.cc \ + $$V8SRC/x64/deoptimizer-x64.cc \ + $$V8SRC/x64/disasm-x64.cc \ + $$V8SRC/x64/frames-x64.cc \ + $$V8SRC/x64/full-codegen-x64.cc \ + $$V8SRC/x64/ic-x64.cc \ + $$V8SRC/x64/lithium-codegen-x64.cc \ + $$V8SRC/x64/lithium-gap-resolver-x64.cc \ + $$V8SRC/x64/lithium-x64.cc \ + $$V8SRC/x64/macro-assembler-x64.cc \ + $$V8SRC/x64/regexp-macro-assembler-x64.cc \ + $$V8SRC/x64/stub-cache-x64.cc +} + +unix:!symbian:!macx { +SOURCES += \ + $$V8SRC/platform-linux.cc \ + $$V8SRC/platform-posix.cc +} + +#os:macos +macx { +SOURCES += \ + $$V8SRC/platform-macos.cc \ + $$V8SRC/platform-posix.cc +} + +win32 { +SOURCES += \ + $$V8SRC/platform-win32.cc +LIBS += Ws2_32.lib Winmm.lib +win32-msvc*: QMAKE_CXXFLAGS += -wd4100 -wd 4291 -wd4351 -wd4355 -wd4800 +win32-msvc*:arch_i386: DEFINES += _USE_32BIT_TIME_T +} + +#mode:debug +CONFIG(debug) { + SOURCES += \ + $$V8SRC/objects-debug.cc \ + $$V8SRC/prettyprinter.cc \ + $$V8SRC/regexp-macro-assembler-tracer.cc +} + +V8_LIBRARY_FILES = \ + $$V8SRC/runtime.js \ + $$V8SRC/v8natives.js \ + $$V8SRC/array.js \ + $$V8SRC/string.js \ + $$V8SRC/uri.js \ + $$V8SRC/math.js \ + $$V8SRC/messages.js \ + $$V8SRC/apinatives.js \ + $$V8SRC/date.js \ + $$V8SRC/regexp.js \ + $$V8SRC/json.js \ + $$V8SRC/liveedit-debugger.js \ + $$V8SRC/mirror-debugger.js \ + $$V8SRC/debug-debugger.js + +v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp $$V8_GENERATED_SOURCES_DIR/libraries-empty.cpp CORE +v8_js2c.commands += $$V8SRC/macros.py ${QMAKE_FILE_IN} +v8_js2c.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp +v8_js2c.input = V8_LIBRARY_FILES +v8_js2c.variable_out = SOURCES +v8_js2c.dependency_type = TYPE_C +v8_js2c.depends = $$V8DIR/tools/js2c.py $$V8SRC/macros.py +v8_js2c.CONFIG += combine +v8_js2c.name = generating[v8] ${QMAKE_FILE_IN} +silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands +QMAKE_EXTRA_COMPILERS += v8_js2c diff --git a/src/v8/v8.pro b/src/v8/v8.pro new file mode 100644 index 0000000000..eb14ca9a19 --- /dev/null +++ b/src/v8/v8.pro @@ -0,0 +1,24 @@ +load(qt_module) + +TARGET = QtV8 +QPRO_PWD = $$PWD +QT = + +CONFIG += module +MODULE_PRI = ../modules/qt_v8.pri + +win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 + +load(qt_module_config) + +# Remove includepaths that were added by qt_module_config. +# These cause compilation of V8 to fail because they appear before +# 3rdparty/v8/src; 3rdparty/v8/src/v8.h will then be "shadowed" by +# the public v8.h API header (they are not the same!). +INCLUDEPATH -= $$MODULE_PRIVATE_INCLUDES +INCLUDEPATH -= $$MODULE_PRIVATE_INCLUDES/$$TARGET +INCLUDEPATH -= $$MODULE_INCLUDES $$MODULE_INCLUDES/.. + +HEADERS += $$QT_SOURCE_TREE/src/v8/qtv8version.h + +include(v8.pri) diff --git a/src/v8/v8base.pri b/src/v8/v8base.pri new file mode 100644 index 0000000000..f0d7c00451 --- /dev/null +++ b/src/v8/v8base.pri @@ -0,0 +1,19 @@ +V8DIR = $$(V8DIR) +isEmpty(V8DIR) { + V8DIR = $$PWD/../3rdparty/v8 +} else { + message(using external V8 from $$V8DIR) +} + +*-g++*: { + QMAKE_CFLAGS_WARN_ON += -Wno-unused-parameter + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter + + # mksnapshot hangs if gcc 4.5 is used + # for reference look at http://code.google.com/p/v8/issues/detail?id=884 + equals(QT_GCC_MAJOR_VERSION, 4): equals(QT_GCC_MINOR_VERSION, 5) { + message(because of a bug in gcc / v8 we need to add -fno-strict-aliasing) + QMAKE_CFLAGS += -fno-strict-aliasing + QMAKE_CXXFLAGS += -fno-strict-aliasing + } +} |