Revert "Update V8"

This reverts commit 1c4a5fcab76d1b769a4c0369d40dd0dd7c0e7495

Several of the qtdeclarative tests and examples are dying randomly with messages like this:
> 
> #
> # Fatal error in ../3rdparty/v8/src/objects-inl.h, line 2169
> # CHECK(object->IsJSFunction()) failed
> #
> 
> 
> ==== Stack trace ============================================
> 
> 
> ==== Details ================================================
> 
> ==== Key         ============================================
> 
> =====================
> 
> Aborted (core dumped)

Change-Id: Iebaa2497a6f6ef616ef4c3576c217d2a8a2c1ea5
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
This commit is contained in:
Kent Hansen 2011-10-20 10:31:42 +02:00 committed by Qt by Nokia
parent 3885a45e48
commit ce5adc7684
24 changed files with 2702 additions and 1567 deletions

2
src/3rdparty/v8 vendored

@ -1 +1 @@
Subproject commit 9c0d93bfae724e29ef63456942d9ddca10ca5825 Subproject commit 8f15248619bb3bf49473dc3ede8a4e631bd5d199

View File

@ -1,25 +1,25 @@
From b0b5bcfbda218aac8e797c19ff6f6de4052d972f Mon Sep 17 00:00:00 2001 From 3dff2e903674d8ab5310d44281b57de36db659c9 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Tue, 4 Oct 2011 15:04:21 +1000 Date: Mon, 23 May 2011 15:47:20 +1000
Subject: [PATCH 01/11] Add hashing and comparison methods to v8::String Subject: [PATCH 01/16] Add hashing and comparison methods to v8::String
This allows us to more rapidly search for a v8::String inside a hash This allows us to more rapidly search for a v8::String inside
of QStrings. a hash of QStrings.
--- ---
include/v8.h | 45 +++++++++++++++++++++++++++++ include/v8.h | 45 +++++++++++++++++++++++++++++++
src/api.cc | 51 +++++++++++++++++++++++++++++++++ src/api.cc | 43 +++++++++++++++++++++++++++++
src/heap-inl.h | 2 + src/heap-inl.h | 2 +
src/heap.cc | 3 ++ src/heap.cc | 3 ++
src/objects-inl.h | 1 + src/objects-inl.h | 1 +
src/objects.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/objects.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/objects.h | 10 ++++++- src/objects.h | 15 +++++++++-
7 files changed, 192 insertions(+), 2 deletions(-) 7 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index 73b7fbe..86ea70f 100644 index d15d024..be1ee71 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -1021,6 +1021,49 @@ class String : public Primitive { @@ -994,6 +994,49 @@ class String : public Primitive {
V8EXPORT int Utf8Length() const; V8EXPORT int Utf8Length() const;
/** /**
@ -69,30 +69,29 @@ index 73b7fbe..86ea70f 100644
* Write the contents of the string to an external buffer. * Write the contents of the string to an external buffer.
* If no arguments are given, expects the buffer to be large * If no arguments are given, expects the buffer to be large
* enough to hold the entire string and NULL terminator. Copies * enough to hold the entire string and NULL terminator. Copies
@@ -1051,6 +1094,8 @@ class String : public Primitive { @@ -1023,6 +1066,8 @@ class String : public Primitive {
NO_NULL_TERMINATION = 2 HINT_MANY_WRITES_EXPECTED = 1
}; };
+ V8EXPORT uint16_t GetCharacter(int index); + V8EXPORT uint16_t GetCharacter(int index);
+ +
// 16-bit character codes.
V8EXPORT int Write(uint16_t* buffer, V8EXPORT int Write(uint16_t* buffer,
int start = 0, int start = 0,
int length = -1,
diff --git a/src/api.cc b/src/api.cc diff --git a/src/api.cc b/src/api.cc
index 7ae01d1..2d205fd 100644 index a2373cd..381935b 100644
--- a/src/api.cc --- a/src/api.cc
+++ b/src/api.cc +++ b/src/api.cc
@@ -3652,6 +3652,57 @@ int String::Utf8Length() const { @@ -3284,6 +3284,49 @@ int String::Utf8Length() const {
return str->Utf8Length();
} }
+uint32_t String::Hash() const { +uint32_t String::Hash() const {
+ i::Handle<i::String> str = Utils::OpenHandle(this); + i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0; + if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
+ return str->Hash(); + return str->Hash();
+} +}
+ +
+
+String::CompleteHashData String::CompleteHash() const { +String::CompleteHashData String::CompleteHash() const {
+ i::Handle<i::String> str = Utils::OpenHandle(this); + i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData(); + if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData();
@ -104,47 +103,40 @@ index 7ae01d1..2d205fd 100644
+ return result; + return result;
+} +}
+ +
+
+uint32_t String::ComputeHash(uint16_t *string, int length) { +uint32_t String::ComputeHash(uint16_t *string, int length) {
+ return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift; + return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift;
+} +}
+ +
+
+uint32_t String::ComputeHash(char *string, int length) { +uint32_t String::ComputeHash(char *string, int length) {
+ return i::HashSequentialString<char>(string, length) >> i::String::kHashShift; + return i::HashSequentialString<char>(string, length) >> i::String::kHashShift;
+} +}
+ +
+
+uint16_t String::GetCharacter(int index) +uint16_t String::GetCharacter(int index)
+{ +{
+ i::Handle<i::String> str = Utils::OpenHandle(this); + i::Handle<i::String> str = Utils::OpenHandle(this);
+ return str->Get(index); + return str->Get(index);
+} +}
+ +
+
+bool String::Equals(uint16_t *string, int length) { +bool String::Equals(uint16_t *string, int length) {
+ i::Handle<i::String> str = Utils::OpenHandle(this); + i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; + if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
+ return str->SlowEqualsExternal(string, length); + return str->SlowEqualsExternal(string, length);
+} +}
+ +
+
+bool String::Equals(char *string, int length) +bool String::Equals(char *string, int length)
+{ +{
+ i::Handle<i::String> str = Utils::OpenHandle(this); + i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0; + if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
+ return str->SlowEqualsExternal(string, length); + return str->SlowEqualsExternal(string, length);
+} +}
+
+
int String::WriteUtf8(char* buffer, int String::WriteUtf8(char* buffer,
int capacity, int capacity,
int* nchars_ref,
diff --git a/src/heap-inl.h b/src/heap-inl.h diff --git a/src/heap-inl.h b/src/heap-inl.h
index 4bd893e..a4dfa5a 100644 index 99737ed..f4fce7b 100644
--- a/src/heap-inl.h --- a/src/heap-inl.h
+++ b/src/heap-inl.h +++ b/src/heap-inl.h
@@ -105,6 +105,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, @@ -93,6 +93,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
String* answer = String::cast(result); String* answer = String::cast(result);
answer->set_length(str.length()); answer->set_length(str.length());
answer->set_hash_field(hash_field); answer->set_hash_field(hash_field);
@ -152,7 +144,7 @@ index 4bd893e..a4dfa5a 100644
ASSERT_EQ(size, answer->Size()); ASSERT_EQ(size, answer->Size());
@@ -138,6 +139,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str, @@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
String* answer = String::cast(result); String* answer = String::cast(result);
answer->set_length(str.length()); answer->set_length(str.length());
answer->set_hash_field(hash_field); answer->set_hash_field(hash_field);
@ -161,18 +153,18 @@ index 4bd893e..a4dfa5a 100644
ASSERT_EQ(size, answer->Size()); ASSERT_EQ(size, answer->Size());
diff --git a/src/heap.cc b/src/heap.cc diff --git a/src/heap.cc b/src/heap.cc
index 522861d..0dfd453 100644 index 2b6c11f..930c97b 100644
--- a/src/heap.cc --- a/src/heap.cc
+++ b/src/heap.cc +++ b/src/heap.cc
@@ -4061,6 +4061,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, @@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
String* answer = String::cast(result); String* answer = String::cast(result);
answer->set_length(chars); answer->set_length(chars);
answer->set_hash_field(hash_field); answer->set_hash_field(hash_field);
+ SeqString::cast(answer)->set_symbol_id(0); + SeqString::cast(result)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size()); ASSERT_EQ(size, answer->Size());
@@ -4103,6 +4104,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { @@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
HeapObject::cast(result)->set_map(ascii_string_map()); HeapObject::cast(result)->set_map(ascii_string_map());
String::cast(result)->set_length(length); String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField); String::cast(result)->set_hash_field(String::kEmptyHashField);
@ -180,7 +172,7 @@ index 522861d..0dfd453 100644
ASSERT_EQ(size, HeapObject::cast(result)->Size()); ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result; return result;
} }
@@ -4138,6 +4140,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length, @@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length,
HeapObject::cast(result)->set_map(string_map()); HeapObject::cast(result)->set_map(string_map());
String::cast(result)->set_length(length); String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField); String::cast(result)->set_hash_field(String::kEmptyHashField);
@ -189,11 +181,11 @@ index 522861d..0dfd453 100644
return result; return result;
} }
diff --git a/src/objects-inl.h b/src/objects-inl.h diff --git a/src/objects-inl.h b/src/objects-inl.h
index baf271f..73d0ac9 100644 index 65aec5d..c82080d 100644
--- a/src/objects-inl.h --- a/src/objects-inl.h
+++ b/src/objects-inl.h +++ b/src/objects-inl.h
@@ -2192,6 +2192,7 @@ SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) @@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset)
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
SMI_ACCESSORS(String, length, kLengthOffset) SMI_ACCESSORS(String, length, kLengthOffset)
+SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset) +SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset)
@ -201,13 +193,13 @@ index baf271f..73d0ac9 100644
uint32_t String::hash_field() { uint32_t String::hash_field() {
diff --git a/src/objects.cc b/src/objects.cc diff --git a/src/objects.cc b/src/objects.cc
index 45ae49d..fe5bf97 100644 index df61956..dc4b260 100644
--- a/src/objects.cc --- a/src/objects.cc
+++ b/src/objects.cc +++ b/src/objects.cc
@@ -6242,6 +6242,71 @@ static inline bool CompareStringContentsPartial(Isolate* isolate, @@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate,
}
} }
+bool String::SlowEqualsExternal(uc16 *string, int length) { +bool String::SlowEqualsExternal(uc16 *string, int length) {
+ int len = this->length(); + int len = this->length();
+ if (len != length) return false; + if (len != length) return false;
@ -220,14 +212,13 @@ index 45ae49d..fe5bf97 100644
+ String* lhs = this->TryFlattenGetString(); + String* lhs = this->TryFlattenGetString();
+ +
+ if (lhs->IsFlat()) { + if (lhs->IsFlat()) {
+ String::FlatContent lhs_content = lhs->GetFlatContent();
+ if (lhs->IsAsciiRepresentation()) { + if (lhs->IsAsciiRepresentation()) {
+ Vector<const char> vec1 = lhs_content.ToAsciiVector(); + Vector<const char> vec1 = lhs->ToAsciiVector();
+ VectorIterator<char> buf1(vec1); + VectorIterator<char> buf1(vec1);
+ VectorIterator<uc16> ib(string, length); + VectorIterator<uc16> ib(string, length);
+ return CompareStringContents(&buf1, &ib); + return CompareStringContents(&buf1, &ib);
+ } else { + } else {
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector(); + Vector<const uc16> vec1 = lhs->ToUC16Vector();
+ Vector<const uc16> vec2(string, length); + Vector<const uc16> vec2(string, length);
+ return CompareRawStringContents(vec1, vec2); + return CompareRawStringContents(vec1, vec2);
+ } + }
@ -239,7 +230,6 @@ index 45ae49d..fe5bf97 100644
+ } + }
+} +}
+ +
+
+bool String::SlowEqualsExternal(char *string, int length) +bool String::SlowEqualsExternal(char *string, int length)
+{ +{
+ int len = this->length(); + int len = this->length();
@ -259,11 +249,10 @@ index 45ae49d..fe5bf97 100644
+ } + }
+ +
+ if (lhs->IsFlat()) { + if (lhs->IsFlat()) {
+ String::FlatContent lhs_content = lhs->GetFlatContent(); + Vector<const uc16> vec1 = lhs->ToUC16Vector();
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector(); + VectorIterator<const uc16> buf1(vec1);
+ VectorIterator<const uc16> buf1(vec1); + VectorIterator<char> buf2(string, length);
+ VectorIterator<char> buf2(string, length); + return CompareStringContents(&buf1, &buf2);
+ return CompareStringContents(&buf1, &buf2);
+ } else { + } else {
+ Isolate* isolate = GetIsolate(); + Isolate* isolate = GetIsolate();
+ isolate->objects_string_compare_buffer_a()->Reset(0, lhs); + isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
@ -271,12 +260,10 @@ index 45ae49d..fe5bf97 100644
+ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib); + return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib);
+ } + }
+} +}
+
+
bool String::SlowEquals(String* other) { bool String::SlowEquals(String* other) {
// Fast check: negative check with lengths. // Fast check: negative check with lengths.
int len = length(); @@ -8655,9 +8715,24 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
@@ -10103,9 +10168,24 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
MaybeObject* AsObject() { MaybeObject* AsObject() {
if (hash_field_ == 0) Hash(); if (hash_field_ == 0) Hash();
@ -301,12 +288,12 @@ index 45ae49d..fe5bf97 100644
+Atomic32 AsciiSymbolKey::next_symbol_id = 1; +Atomic32 AsciiSymbolKey::next_symbol_id = 1;
class SubStringAsciiSymbolKey : public HashTableKey { class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
diff --git a/src/objects.h b/src/objects.h diff --git a/src/objects.h b/src/objects.h
index 5a1a4a3..eb4eb0e 100644 index e966b3d..6e26f57 100644
--- a/src/objects.h --- a/src/objects.h
+++ b/src/objects.h +++ b/src/objects.h
@@ -5952,6 +5952,9 @@ class String: public HeapObject { @@ -5359,6 +5359,9 @@ class String: public HeapObject {
bool IsAsciiEqualTo(Vector<const char> str); bool IsAsciiEqualTo(Vector<const char> str);
bool IsTwoByteEqualTo(Vector<const uc16> str); bool IsTwoByteEqualTo(Vector<const uc16> str);
@ -316,21 +303,42 @@ index 5a1a4a3..eb4eb0e 100644
// Return a UTF8 representation of the string. The string is null // Return a UTF8 representation of the string. The string is null
// terminated but may optionally contain nulls. Length is returned // terminated but may optionally contain nulls. Length is returned
// in length_output if length_output is not a null pointer The string // in length_output if length_output is not a null pointer The string
@@ -6207,8 +6210,13 @@ class SeqString: public String { @@ -5610,9 +5613,17 @@ class String: public HeapObject {
// Casting. class SeqString: public String {
static inline SeqString* cast(Object* obj); public:
+ // Get and set the symbol id of the string + // Get and set the symbol id of the string
+ inline int symbol_id(); + inline int symbol_id();
+ inline void set_symbol_id(int value); + 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. // Layout description.
- static const int kHeaderSize = String::kSize; - static const int kHeaderSize = String::kSize;
+ static const int kSymbolIdOffset = String::kSize; + static const int kHeaderSize = SeqString::kSize;
+ static const int kHeaderSize = kSymbolIdOffset + kPointerSize; static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize);
// Shortcuts for templates that know their string-type exactly. // Maximal memory usage for a single sequential ASCII string.
bool IsExternalAsciiString() { @@ -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.4.4 1.7.4.4

View File

@ -0,0 +1,118 @@
From 01f7bd262fb1be893fe4bdc6b98a1b43c5a0bb7d 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/16] 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.4.4

View File

@ -1,7 +1,7 @@
From a80d89daacb698b72f59cad5b83c1f1633a98c9f Mon Sep 17 00:00:00 2001 From 530ded6ea634bccb96652cd3e0cf67725449ed63 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Tue, 4 Oct 2011 15:30:20 +1000 Date: Mon, 23 May 2011 16:21:02 +1000
Subject: [PATCH 02/11] Add a "fallback" mode for named property interceptors Subject: [PATCH 03/16] Add a "fallback" mode for named property interceptors
By default interceptors are called before the normal property By default interceptors are called before the normal property
resolution on objects. When an interceptor is installed as a resolution on objects. When an interceptor is installed as a
@ -12,22 +12,22 @@ In the case of a global object having an fallback interceptor,
the interceptor is not invoked at all for var or function the interceptor is not invoked at all for var or function
declarations. declarations.
--- ---
include/v8.h | 7 +++++++ include/v8.h | 8 ++++++++
src/api.cc | 29 +++++++++++++++++++++++++++++ src/api.cc | 29 +++++++++++++++++++++++++++++
src/factory.cc | 3 +++ src/factory.cc | 4 ++++
src/handles.cc | 6 ++++-- src/handles.cc | 6 ++++--
src/handles.h | 3 ++- src/handles.h | 3 ++-
src/objects-inl.h | 15 +++++++++++++++ src/objects-inl.h | 16 ++++++++++++++++
src/objects.cc | 24 +++++++++++++++++------- src/objects.cc | 22 ++++++++++++++++------
src/objects.h | 16 ++++++++++++---- src/objects.h | 18 ++++++++++++++----
src/runtime.cc | 11 ++++++----- src/runtime.cc | 11 ++++++-----
9 files changed, 95 insertions(+), 19 deletions(-) 9 files changed, 99 insertions(+), 18 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index 86ea70f..d2e6c32 100644 index be1ee71..bb31ea0 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -2305,6 +2305,7 @@ class V8EXPORT FunctionTemplate : public Template { @@ -2170,6 +2170,7 @@ class V8EXPORT FunctionTemplate : public Template {
NamedPropertyQuery query, NamedPropertyQuery query,
NamedPropertyDeleter remover, NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator, NamedPropertyEnumerator enumerator,
@ -35,24 +35,25 @@ index 86ea70f..d2e6c32 100644
Handle<Value> data); Handle<Value> data);
void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter, IndexedPropertySetter setter,
@@ -2388,6 +2389,12 @@ class V8EXPORT ObjectTemplate : public Template { @@ -2254,6 +2255,13 @@ class V8EXPORT ObjectTemplate : public Template {
NamedPropertyDeleter deleter = 0,
NamedPropertyEnumerator enumerator = 0, NamedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>()); Handle<Value> data = Handle<Value>());
+ void SetFallbackPropertyHandler(NamedPropertyGetter getter, + void SetFallbackPropertyHandler(NamedPropertyGetter getter,
+ NamedPropertySetter setter = 0, + NamedPropertySetter setter = 0,
+ NamedPropertyQuery query = 0, + NamedPropertyQuery query = 0,
+ NamedPropertyDeleter deleter = 0, + NamedPropertyDeleter deleter = 0,
+ NamedPropertyEnumerator enumerator = 0, + NamedPropertyEnumerator enumerator = 0,
+ Handle<Value> data = Handle<Value>()); + Handle<Value> data = Handle<Value>());
+
/** /**
* Sets an indexed property handler on the object template. * Sets an indexed property handler on the object template.
*
diff --git a/src/api.cc b/src/api.cc diff --git a/src/api.cc b/src/api.cc
index 2d205fd..e4dd694 100644 index 381935b..8b0b32a 100644
--- a/src/api.cc --- a/src/api.cc
+++ b/src/api.cc +++ b/src/api.cc
@@ -1123,6 +1123,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( @@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
NamedPropertyQuery query, NamedPropertyQuery query,
NamedPropertyDeleter remover, NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator, NamedPropertyEnumerator enumerator,
@ -60,7 +61,7 @@ index 2d205fd..e4dd694 100644
Handle<Value> data) { Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, if (IsDeadCheck(isolate,
@@ -1141,6 +1142,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler( @@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
@ -68,7 +69,7 @@ index 2d205fd..e4dd694 100644
if (data.IsEmpty()) data = v8::Undefined(); if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data)); obj->set_data(*Utils::OpenHandle(*data));
@@ -1285,6 +1287,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, @@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
query, query,
remover, remover,
enumerator, enumerator,
@ -84,7 +85,7 @@ index 2d205fd..e4dd694 100644
+ NamedPropertyEnumerator enumerator, + NamedPropertyEnumerator enumerator,
+ Handle<Value> data) { + Handle<Value> data) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) { + if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) {
+ return; + return;
+ } + }
+ ENTER_V8(isolate); + ENTER_V8(isolate);
@ -103,13 +104,14 @@ index 2d205fd..e4dd694 100644
} }
diff --git a/src/factory.cc b/src/factory.cc diff --git a/src/factory.cc b/src/factory.cc
index 00fc6bb..2338cda 100644 index 7dee66f..dcdc645 100644
--- a/src/factory.cc --- a/src/factory.cc
+++ b/src/factory.cc +++ b/src/factory.cc
@@ -1180,6 +1180,9 @@ Handle<JSFunction> Factory::CreateApiFunction( @@ -1058,6 +1058,10 @@ Handle<JSFunction> Factory::CreateApiFunction(
// Set interceptor information in the map. // Set interceptor information in the map.
if (!obj->named_property_handler()->IsUndefined()) { if (!obj->named_property_handler()->IsUndefined()) {
map->set_has_named_interceptor(); map->set_has_named_interceptor();
+
+ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler()); + InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler());
+ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value(); + bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value();
+ map->set_named_interceptor_is_fallback(is_fallback); + map->set_named_interceptor_is_fallback(is_fallback);
@ -117,10 +119,10 @@ index 00fc6bb..2338cda 100644
if (!obj->indexed_property_handler()->IsUndefined()) { if (!obj->indexed_property_handler()->IsUndefined()) {
map->set_has_indexed_interceptor(); map->set_has_indexed_interceptor();
diff --git a/src/handles.cc b/src/handles.cc diff --git a/src/handles.cc b/src/handles.cc
index ce4258d..104fc9c 100644 index 326de86..dd3a86c 100644
--- a/src/handles.cc --- a/src/handles.cc
+++ b/src/handles.cc +++ b/src/handles.cc
@@ -265,9 +265,11 @@ Handle<Object> SetProperty(Handle<JSReceiver> object, @@ -262,9 +262,11 @@ Handle<Object> SetProperty(Handle<JSObject> object,
Handle<String> key, Handle<String> key,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes, PropertyAttributes attributes,
@ -135,10 +137,10 @@ index ce4258d..104fc9c 100644
} }
diff --git a/src/handles.h b/src/handles.h diff --git a/src/handles.h b/src/handles.h
index 8dcca3e..babe763 100644 index 3839f37..4b42506 100644
--- a/src/handles.h --- a/src/handles.h
+++ b/src/handles.h +++ b/src/handles.h
@@ -192,7 +192,8 @@ Handle<Object> SetProperty(Handle<JSReceiver> object, @@ -188,7 +188,8 @@ Handle<Object> SetProperty(Handle<JSObject> object,
Handle<String> key, Handle<String> key,
Handle<Object> value, Handle<Object> value,
PropertyAttributes attributes, PropertyAttributes attributes,
@ -149,14 +151,13 @@ index 8dcca3e..babe763 100644
Handle<Object> SetProperty(Handle<Object> object, Handle<Object> SetProperty(Handle<Object> object,
Handle<Object> key, Handle<Object> key,
diff --git a/src/objects-inl.h b/src/objects-inl.h diff --git a/src/objects-inl.h b/src/objects-inl.h
index 73d0ac9..35fbea5 100644 index cce3edd..6aaca2f 100644
--- a/src/objects-inl.h --- a/src/objects-inl.h
+++ b/src/objects-inl.h +++ b/src/objects-inl.h
@@ -2864,6 +2864,20 @@ void Map::set_is_shared(bool value) { @@ -2521,6 +2521,21 @@ bool Map::is_shared() {
bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
} }
+
+void Map::set_named_interceptor_is_fallback(bool value) +void Map::set_named_interceptor_is_fallback(bool value)
+{ +{
+ if (value) { + if (value) {
@ -170,10 +171,12 @@ index 73d0ac9..35fbea5 100644
+{ +{
+ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0; + return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
+} +}
+
+
JSFunction* Map::unchecked_constructor() { JSFunction* Map::unchecked_constructor() {
@@ -3350,6 +3364,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset) return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
}
@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset) ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset) ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
@ -182,73 +185,71 @@ index 73d0ac9..35fbea5 100644
ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
diff --git a/src/objects.cc b/src/objects.cc diff --git a/src/objects.cc b/src/objects.cc
index fe5bf97..8e1773f 100644 index 79d7240..15e2cdb 100644
--- a/src/objects.cc --- a/src/objects.cc
+++ b/src/objects.cc +++ b/src/objects.cc
@@ -1838,9 +1838,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( @@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
MaybeObject* JSReceiver::SetProperty(String* name, MaybeObject* JSObject::SetProperty(String* name,
Object* value, Object* value,
PropertyAttributes attributes, PropertyAttributes attributes,
- StrictModeFlag strict_mode) { - StrictModeFlag strict_mode) {
+ StrictModeFlag strict_mode, + StrictModeFlag strict_mode,
+ bool skip_fallback_interceptor) { + bool skip_fallback_interceptor) {
LookupResult result; LookupResult result;
- LocalLookup(name, &result); - LocalLookup(name, &result);
+ LocalLookup(name, &result, skip_fallback_interceptor); + LocalLookup(name, &result, skip_fallback_interceptor);
return SetProperty(&result, name, value, attributes, strict_mode); return SetProperty(&result, name, value, attributes, strict_mode);
} }
@@ -3832,7 +3833,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { @@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
} }
-void JSReceiver::LocalLookup(String* name, LookupResult* result) { -void JSObject::LocalLookup(String* name, LookupResult* result) {
+void JSReceiver::LocalLookup(String* name, LookupResult* result, +void JSObject::LocalLookup(String* name, LookupResult* result,
+ bool skip_fallback_interceptor) { + bool skip_fallback_interceptor) {
ASSERT(name->IsString()); ASSERT(name->IsString());
Heap* heap = GetHeap(); Heap* heap = GetHeap();
@@ -3864,23 +3866,31 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) { @@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) {
} }
// Check for lookup interceptor except when bootstrapping. // Check for lookup interceptor except when bootstrapping.
- if (js_object->HasNamedInterceptor() && - if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
- !heap->isolate()->bootstrapper()->IsActive()) { + bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive();
+ bool wouldIntercept = js_object->HasNamedInterceptor() &&
+ !heap->isolate()->bootstrapper()->IsActive();
+ if (wouldIntercept && !map()->named_interceptor_is_fallback()) { + if (wouldIntercept && !map()->named_interceptor_is_fallback()) {
result->InterceptorResult(js_object); result->InterceptorResult(this);
return; return;
} }
js_object->LocalLookupRealNamedProperty(name, result); LocalLookupRealNamedProperty(name, result);
+ +
+ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() && + if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
+ map()->named_interceptor_is_fallback()) { + map()->named_interceptor_is_fallback()) {
+ result->InterceptorResult(js_object); + result->InterceptorResult(this);
+ return; + return;
+ } + }
} }
-void JSReceiver::Lookup(String* name, LookupResult* result) { -void JSObject::Lookup(String* name, LookupResult* result) {
+void JSReceiver::Lookup(String* name, LookupResult* result, +void JSObject::Lookup(String* name, LookupResult* result,
+ bool skip_fallback_interceptor) { + bool skip_fallback_interceptor) {
// Ecma-262 3rd 8.6.2.4 // Ecma-262 3rd 8.6.2.4
Heap* heap = GetHeap(); Heap* heap = GetHeap();
for (Object* current = this; for (Object* current = this;
current != heap->null_value(); current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) { current = JSObject::cast(current)->GetPrototype()) {
- JSReceiver::cast(current)->LocalLookup(name, result); - JSObject::cast(current)->LocalLookup(name, result);
+ JSReceiver::cast(current)->LocalLookup(name, result, skip_fallback_interceptor); + JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor);
if (result->IsProperty()) return; if (result->IsProperty()) return;
} }
result->NotFound(); result->NotFound();
diff --git a/src/objects.h b/src/objects.h diff --git a/src/objects.h b/src/objects.h
index eb4eb0e..b974756 100644 index 07e1089..a209cd0 100644
--- a/src/objects.h --- a/src/objects.h
+++ b/src/objects.h +++ b/src/objects.h
@@ -1332,7 +1332,8 @@ class JSReceiver: public HeapObject { @@ -1405,7 +1405,8 @@ class JSObject: public HeapObject {
MUST_USE_RESULT MaybeObject* SetProperty(String* key, MUST_USE_RESULT MaybeObject* SetProperty(String* key,
Object* value, Object* value,
PropertyAttributes attributes, PropertyAttributes attributes,
@ -258,7 +259,7 @@ index eb4eb0e..b974756 100644
MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result, MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
String* key, String* key,
Object* value, Object* value,
@@ -1381,8 +1382,8 @@ class JSReceiver: public HeapObject { @@ -1637,8 +1638,8 @@ class JSObject: public HeapObject {
// Lookup a property. If found, the result is valid and has // Lookup a property. If found, the result is valid and has
// detailed information. // detailed information.
@ -267,28 +268,30 @@ index eb4eb0e..b974756 100644
+ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); + void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
+ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false); + void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
protected: // The following lookup functions skip interceptors.
Smi* GenerateIdentityHash(); void LocalLookupRealNamedProperty(String* name, LookupResult* result);
@@ -4071,6 +4072,10 @@ class Map: public HeapObject { @@ -3714,6 +3715,12 @@ class Map: public HeapObject {
inline void set_is_access_check_needed(bool access_check_needed); inline void set_is_access_check_needed(bool access_check_needed);
inline bool is_access_check_needed(); inline bool is_access_check_needed();
+
+ // Whether the named interceptor is a fallback interceptor or not + // Whether the named interceptor is a fallback interceptor or not
+ inline void set_named_interceptor_is_fallback(bool value); + inline void set_named_interceptor_is_fallback(bool value);
+ inline bool named_interceptor_is_fallback(); + inline bool named_interceptor_is_fallback();
+
+ +
// [prototype]: implicit prototype object. // [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object) DECL_ACCESSORS(prototype, Object)
@@ -4307,6 +4312,7 @@ class Map: public HeapObject { @@ -3904,6 +3911,7 @@ class Map: public HeapObject {
static const int kHasExternalArrayElements = 6;
// Bit positions for bit field 3 // Bit positions for bit field 3
static const int kIsShared = 0; + static const int kNamedInterceptorIsFallback = 0;
+ static const int kNamedInterceptorIsFallback = 1;
// Layout of the default cache. It holds alternating name and code objects. // Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2; static const int kCodeCacheEntrySize = 2;
@@ -7142,6 +7148,7 @@ class InterceptorInfo: public Struct { @@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct {
DECL_ACCESSORS(deleter, Object) DECL_ACCESSORS(deleter, Object)
DECL_ACCESSORS(enumerator, Object) DECL_ACCESSORS(enumerator, Object)
DECL_ACCESSORS(data, Object) DECL_ACCESSORS(data, Object)
@ -296,7 +299,7 @@ index eb4eb0e..b974756 100644
static inline InterceptorInfo* cast(Object* obj); static inline InterceptorInfo* cast(Object* obj);
@@ -7161,7 +7168,8 @@ class InterceptorInfo: public Struct { @@ -6295,7 +6304,8 @@ class InterceptorInfo: public Struct {
static const int kDeleterOffset = kQueryOffset + kPointerSize; static const int kDeleterOffset = kQueryOffset + kPointerSize;
static const int kEnumeratorOffset = kDeleterOffset + kPointerSize; static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
static const int kDataOffset = kEnumeratorOffset + kPointerSize; static const int kDataOffset = kEnumeratorOffset + kPointerSize;
@ -307,48 +310,48 @@ index eb4eb0e..b974756 100644
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo); DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
diff --git a/src/runtime.cc b/src/runtime.cc diff --git a/src/runtime.cc b/src/runtime.cc
index 89abf38..5a850e9 100644 index 7335da8..660352c 100644
--- a/src/runtime.cc --- a/src/runtime.cc
+++ b/src/runtime.cc +++ b/src/runtime.cc
@@ -1236,7 +1236,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { @@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
// Lookup the property in the global object, and don't set the // Lookup the property in the global object, and don't set the
// value of the variable if the property is already there. // value of the variable if the property is already there.
LookupResult lookup; LookupResult lookup;
- global->Lookup(*name, &lookup); - global->Lookup(*name, &lookup);
+ global->Lookup(*name, &lookup, true); + global->Lookup(*name, &lookup, true);
if (lookup.IsProperty()) { if (lookup.IsProperty()) {
// We found an existing property. Unless it was an interceptor // Determine if the property is local by comparing the holder
// that claims the property is absent, skip this declaration. // against the global object. The information will be used to
@@ -1263,7 +1263,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { @@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
} }
LookupResult lookup; LookupResult lookup;
- global->LocalLookup(*name, &lookup); - global->LocalLookup(*name, &lookup);
+ global->LocalLookup(*name, &lookup, true); + global->LocalLookup(*name, &lookup, true);
// Compute the property attributes. According to ECMA-262, section PropertyAttributes attributes = is_const_property
// 13, page 71, the property must be read-only and ? static_cast<PropertyAttributes>(base | READ_ONLY)
@@ -1306,7 +1306,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { @@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
name, name,
value, value,
static_cast<PropertyAttributes>(attr), attributes,
- strict_mode)); - strict_mode));
+ strict_mode, + strict_mode,
+ true)); + true));
} }
} }
@@ -1442,7 +1443,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { @@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
while (object->IsJSObject() && JSObject* real_holder = global;
JSObject::cast(object)->map()->is_hidden_prototype()) { LookupResult lookup;
JSObject* raw_holder = JSObject::cast(object); while (true) {
- raw_holder->LocalLookup(*name, &lookup); - real_holder->LocalLookup(*name, &lookup);
+ raw_holder->LocalLookup(*name, &lookup, true); + real_holder->LocalLookup(*name, &lookup, true);
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) { if (lookup.IsProperty()) {
HandleScope handle_scope(isolate); // Determine if this is a redeclaration of something read-only.
Handle<JSObject> holder(raw_holder); if (lookup.IsReadOnly()) {
@@ -1465,7 +1466,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { @@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
// Reload global in case the loop above performed a GC.
global = isolate->context()->global(); global = isolate->context()->global();
if (assign) { if (assign) {
- return global->SetProperty(*name, args[2], attributes, strict_mode); - return global->SetProperty(*name, args[2], attributes, strict_mode);

View File

@ -1,595 +0,0 @@
From be5bc4e5ea15dd74c2753c30c25a4660598274c3 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Tue, 4 Oct 2011 16:06:09 +1000
Subject: [PATCH 03/11] 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 | 56 +++++++++++++++++++++++++++++++++++++++++++++
src/factory.cc | 11 +++++++++
src/heap-inl.h | 63 +++++++++++++++++++++++++++++++++++---------------
src/heap.cc | 29 +++++++++++++++++------
src/heap.h | 16 ++++++++-----
src/mark-compact.cc | 13 +++++-----
src/objects-inl.h | 35 +++++++++++++++++++++++++++-
src/objects.h | 19 ++++++++++++---
9 files changed, 223 insertions(+), 44 deletions(-)
diff --git a/include/v8.h b/include/v8.h
index d2e6c32..3ef4dd6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1597,6 +1597,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 HasOwnProperty(Handle<String> key);
V8EXPORT bool HasRealNamedProperty(Handle<String> key);
@@ -2466,6 +2485,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 e4dd694..85f0d4b 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1436,6 +1436,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 ---
@@ -4031,6 +4059,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()->NewForeign(static_cast<i::Address>((void *)resource)));
+ }
+ if (!obj->IsSymbol()) {
+ isolate->heap()->external_string_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->IsForeign()) {
+ return reinterpret_cast<v8::Object::ExternalResource*>(i::Foreign::cast(value)->address());
+ } else {
+ return NULL;
+ }
+}
+
+
// --- E n v i r o n m e n t ---
diff --git a/src/factory.cc b/src/factory.cc
index 2338cda..e3cccae 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -1119,15 +1119,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:
@@ -1162,6 +1168,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 a4dfa5a..b121d01 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -222,21 +222,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;
+ } 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->IsForeign()) {
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(Foreign::cast(value)->address());
+ }
+ if (resource) {
+ resource->Dispose();
+ }
}
-
- // Clear the resource pointer in the string.
- *resource_addr = NULL;
}
@@ -556,6 +571,16 @@ void ExternalStringTable::AddString(String* string) {
}
+void ExternalStringTable::AddObject(HeapObject* object) {
+ ASSERT(object->map()->has_external_resource());
+ if (heap_->InNewSpace(object)) {
+ new_space_strings_.Add(object);
+ } else {
+ old_space_strings_.Add(object);
+ }
+}
+
+
void ExternalStringTable::Iterate(ObjectVisitor* v) {
if (!new_space_strings_.is_empty()) {
Object** start = &new_space_strings_[0];
@@ -584,14 +609,14 @@ void ExternalStringTable::Verify() {
}
-void ExternalStringTable::AddOldString(String* string) {
- ASSERT(string->IsExternalString());
- ASSERT(!heap_->InNewSpace(string));
- old_space_strings_.Add(string);
+void ExternalStringTable::AddOldObject(HeapObject* object) {
+ ASSERT(object->IsExternalString() || object->map()->has_external_resource());
+ ASSERT(!heap_->InNewSpace(object));
+ old_space_strings_.Add(object);
}
-void ExternalStringTable::ShrinkNewStrings(int position) {
+void ExternalStringTable::ShrinkNewObjects(int position) {
new_space_strings_.Rewind(position);
Verify();
}
diff --git a/src/heap.cc b/src/heap.cc
index 0dfd453..c730455 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1095,18 +1095,18 @@ void Heap::Scavenge() {
}
-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+HeapObject* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(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());
}
@@ -1122,11 +1122,11 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
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.
@@ -1134,12 +1134,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
++last;
} else {
// String got promoted. Move it to the old string list.
- external_string_table_.AddOldString(target);
+ external_string_table_.AddOldObject(target);
}
}
ASSERT(last <= end);
- external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
+ external_string_table_.ShrinkNewObjects(static_cast<int>(last - start));
}
@@ -6426,6 +6426,19 @@ void ExternalStringTable::CleanUp() {
void ExternalStringTable::TearDown() {
+ for (int i = 0; i < new_space_strings_.length(); ++i) {
+ if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(new_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+ for (int i = 0; i < old_space_strings_.length(); ++i) {
+ if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(old_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+
new_space_strings_.Free();
old_space_strings_.Free();
}
diff --git a/src/heap.h b/src/heap.h
index 4a1e01d..bab4c63 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -243,8 +243,8 @@ class Isolate;
class WeakObjectRetainer;
-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
- Object** pointer);
+typedef HeapObject* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+ Object** pointer);
class StoreBufferRebuilder {
public:
@@ -329,10 +329,14 @@ typedef void (*ScavengingCallback)(Map* map,
// External strings table is a place where all external strings are
// registered. We need to keep track of such strings to properly
// finalize them.
+// The ExternalStringTable can contain both strings and objects with
+// external resources. It was not renamed to make the patch simpler.
class ExternalStringTable {
public:
// Registers an external string.
inline void AddString(String* string);
+ // Registers an external object.
+ inline void AddObject(HeapObject* string);
inline void Iterate(ObjectVisitor* v);
@@ -350,10 +354,10 @@ class ExternalStringTable {
inline void Verify();
- inline void AddOldString(String* string);
+ inline void AddOldObject(HeapObject* string);
// 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.
@@ -849,7 +853,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.
@@ -1662,7 +1666,7 @@ class Heap {
// Performs a minor collection in new generation.
void Scavenge();
- static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
+ static HeapObject* UpdateNewSpaceReferenceInExternalStringTableEntry(
Heap* heap,
Object** pointer);
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index e90a23d..b9ae787 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1521,8 +1521,9 @@ class SymbolTableCleaner : public ObjectVisitor {
// Since no objects have yet been moved we can safely access the map of
// the object.
- if (o->IsExternalString()) {
- heap_->FinalizeExternalString(String::cast(*p));
+ if (o->IsExternalString() ||
+ (o->IsHeapObject() && HeapObject::cast(o)->map()->has_external_resource())) {
+ heap_->FinalizeExternalString(HeapObject::cast(*p));
}
// Set the entry to null_value (as deleted).
*p = heap_->null_value();
@@ -2515,15 +2516,15 @@ static void UpdatePointer(HeapObject** p, HeapObject* object) {
}
-static String* UpdateReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+static HeapObject* UpdateReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord map_word = HeapObject::cast(*p)->map_word();
if (map_word.IsForwardingAddress()) {
- return String::cast(map_word.ToForwardingAddress());
+ return HeapObject::cast(map_word.ToForwardingAddress());
}
- return String::cast(*p);
+ return HeapObject::cast(*p);
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 35fbea5..36af868 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1488,7 +1488,7 @@ 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);
}
@@ -1518,6 +1518,23 @@ void JSObject::SetInternalField(int index, Object* value) {
}
+void JSObject::SetExternalResourceObject(Object *value) {
+ ASSERT(map()->has_external_resource());
+ int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(GetHeap(), this, offset, value);
+}
+
+
+Object *JSObject::GetExternalResourceObject() {
+ if (map()->has_external_resource()) {
+ return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
+ } 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.
@@ -2865,6 +2882,20 @@ bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
}
+void Map::set_has_external_resource(bool value) {
+ if (value) {
+ set_bit_field(bit_field() | (1 << kHasExternalResource));
+ } else {
+ set_bit_field(bit_field() & ~(1 << kHasExternalResource));
+ }
+}
+
+bool Map::has_external_resource()
+{
+ return ((1 << kHasExternalResource) & bit_field()) != 0;
+}
+
+
void Map::set_named_interceptor_is_fallback(bool value)
{
if (value) {
@@ -3396,6 +3427,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 b974756..dea5bbd 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1732,6 +1732,9 @@ class JSObject: public JSReceiver {
inline Object* GetInternalField(int index);
inline void SetInternalField(int index, Object* value);
+ inline void SetExternalResourceObject(Object *);
+ inline Object *GetExternalResourceObject();
+
// The following lookup functions skip interceptors.
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
void LookupRealNamedProperty(String* name, LookupResult* result);
@@ -4003,11 +4006,11 @@ class Map: public HeapObject {
// Tells whether the instance has a call-as-function handler.
inline void set_has_instance_call_handler() {
- set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
+ set_bit_field3(bit_field3() | (1 << kHasInstanceCallHandler));
}
inline bool has_instance_call_handler() {
- return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
+ return ((1 << kHasInstanceCallHandler) & bit_field3()) != 0;
}
inline void set_is_extensible(bool value);
@@ -4076,6 +4079,11 @@ class Map: public HeapObject {
inline void set_named_interceptor_is_fallback(bool value);
inline bool named_interceptor_is_fallback();
+ // 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();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
@@ -4288,7 +4296,7 @@ class Map: public HeapObject {
static const int kHasNamedInterceptor = 3;
static const int kHasIndexedInterceptor = 4;
static const int kIsUndetectable = 5;
- static const int kHasInstanceCallHandler = 6;
+ static const int kHasExternalResource = 6;
static const int kIsAccessCheckNeeded = 7;
// Bit positions for bit field 2
@@ -4313,6 +4321,7 @@ class Map: public HeapObject {
// Bit positions for bit field 3
static const int kIsShared = 0;
static const int kNamedInterceptorIsFallback = 1;
+ static const int kHasInstanceCallHandler = 2;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -7292,6 +7301,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);
@@ -7308,7 +7318,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.4.4

View File

@ -0,0 +1,894 @@
From f9368b52060c31e9532ef26f6cca1a2cb0283f51 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/16] 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 bb31ea0..205e856 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1631,6 +1631,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);
@@ -2332,6 +2351,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..775f787 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.4.4

View File

@ -1,7 +1,7 @@
From 2608243d70a8fcb0335f3520d5de1ac3cd854e87 Mon Sep 17 00:00:00 2001 From 1209b88e96f253cdc19aa4c95e011c84597844f0 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Fri, 14 Oct 2011 17:03:06 +1000 Date: Wed, 25 May 2011 10:36:13 +1000
Subject: [PATCH 05/11] Allow access to the calling script data Subject: [PATCH 06/16] Allow access to the calling script data
--- ---
include/v8.h | 1 + include/v8.h | 1 +
@ -9,10 +9,10 @@ Subject: [PATCH 05/11] Allow access to the calling script data
2 files changed, 13 insertions(+), 0 deletions(-) 2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index 193e2fe..c094d08 100644 index d78ab1f..2bc0ed1 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -3517,6 +3517,7 @@ class V8EXPORT Context { @@ -3337,6 +3337,7 @@ class V8EXPORT Context {
*/ */
static Local<Context> GetCalling(); static Local<Context> GetCalling();
static Local<Object> GetCallingQmlGlobal(); static Local<Object> GetCallingQmlGlobal();
@ -21,10 +21,10 @@ index 193e2fe..c094d08 100644
/** /**
* Sets the security token for the context. To access an object in * Sets the security token for the context. To access an object in
diff --git a/src/api.cc b/src/api.cc diff --git a/src/api.cc b/src/api.cc
index fd718c8..526aa02 100644 index 39767f4..ff74efb 100644
--- a/src/api.cc --- a/src/api.cc
+++ b/src/api.cc +++ b/src/api.cc
@@ -4361,6 +4361,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() { @@ -3976,6 +3976,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
} }
} }

View File

@ -1,18 +1,18 @@
From 9c0d93bfae724e29ef63456942d9ddca10ca5825 Mon Sep 17 00:00:00 2001 From 2a5cf85d7fd7912e516138db03e4cda47cc2a1ab Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Fri, 27 May 2011 13:04:15 +1000 Date: Fri, 27 May 2011 13:04:15 +1000
Subject: [PATCH 11/11] Fix warnings Subject: [PATCH 07/16] Fix warnings
--- ---
include/v8.h | 16 ++++++++-------- include/v8.h | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-) 1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index d995e54..a7b5c8a 100644 index 2bc0ed1..99f4b9a 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -2579,7 +2579,7 @@ class V8EXPORT Extension { // NOLINT @@ -2416,7 +2416,7 @@ class V8EXPORT Extension { // NOLINT
int source_length = -1); const char** deps = 0);
virtual ~Extension() { } virtual ~Extension() { }
virtual v8::Handle<v8::FunctionTemplate> virtual v8::Handle<v8::FunctionTemplate>
- GetNativeFunction(v8::Handle<v8::String> name) { - GetNativeFunction(v8::Handle<v8::String> name) {
@ -20,7 +20,7 @@ index d995e54..a7b5c8a 100644
return v8::Handle<v8::FunctionTemplate>(); return v8::Handle<v8::FunctionTemplate>();
} }
@@ -3946,13 +3946,13 @@ class Internals { @@ -3722,13 +3722,13 @@ class Internals {
return *reinterpret_cast<T*>(addr); return *reinterpret_cast<T*>(addr);
} }

View File

@ -1,7 +1,7 @@
From 1c747846df3be9021aff2b0fc402cdd3a239e86b Mon Sep 17 00:00:00 2001 From a7c491e6e533110a17fe9f7d47cf92a1b2263180 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Wed, 25 May 2011 10:36:13 +1000 Date: Mon, 27 Jun 2011 14:57:28 +1000
Subject: [PATCH 06/11] Add custom object compare callback Subject: [PATCH 08/16] Add custom object compare callback
A global custom object comparison callback can be set with: A global custom object comparison callback can be set with:
V8::SetUserObjectComparisonCallbackFunction() V8::SetUserObjectComparisonCallbackFunction()
@ -14,25 +14,24 @@ compare as equal, even though they are actually different JS object
instances. instances.
--- ---
include/v8.h | 13 +++++++++++++ include/v8.h | 13 +++++++++++++
src/api.cc | 22 ++++++++++++++++++++++ src/api.cc | 19 +++++++++++++++++++
src/arm/code-stubs-arm.cc | 43 +++++++++++++++++++++++++++++++++++++++++-- src/arm/code-stubs-arm.cc | 42 ++++++++++++++++++++++++++++++++++++++++--
src/factory.cc | 8 ++++++++ src/factory.cc | 8 ++++++++
src/ia32/code-stubs-ia32.cc | 39 +++++++++++++++++++++++++++++++++++++++ src/ia32/code-stubs-ia32.cc | 40 ++++++++++++++++++++++++++++++++++++++++
src/isolate.cc | 7 +++++++
src/isolate.h | 8 ++++++++ src/isolate.h | 8 ++++++++
src/objects-inl.h | 21 ++++++++++++++++++--- src/objects-inl.h | 15 +++++++++++++++
src/objects.cc | 8 ++++---- src/objects.h | 10 +++++++++-
src/objects.h | 12 ++++++++++--
src/runtime.cc | 23 +++++++++++++++++++++++ src/runtime.cc | 23 +++++++++++++++++++++++
src/runtime.h | 1 + src/runtime.h | 1 +
src/top.cc | 5 +++++
src/x64/code-stubs-x64.cc | 37 +++++++++++++++++++++++++++++++++++++ src/x64/code-stubs-x64.cc | 37 +++++++++++++++++++++++++++++++++++++
13 files changed, 231 insertions(+), 11 deletions(-) 12 files changed, 218 insertions(+), 3 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index c094d08..6baf2b2 100644 index 99f4b9a..7544deb 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -2501,6 +2501,12 @@ class V8EXPORT ObjectTemplate : public Template { @@ -2366,6 +2366,12 @@ class V8EXPORT ObjectTemplate : public Template {
bool HasExternalResource(); bool HasExternalResource();
void SetHasExternalResource(bool value); void SetHasExternalResource(bool value);
@ -45,18 +44,18 @@ index c094d08..6baf2b2 100644
private: private:
ObjectTemplate(); ObjectTemplate();
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor); static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
@@ -2720,6 +2726,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target, @@ -2566,6 +2572,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
AccessType type, AccessType type,
Local<Value> data); Local<Value> data);
+// --- User Object Comparisoa nCallback --- +// --- 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, +typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
+ Local<Object> rhs); + Local<Object> rhs);
+ +
// --- AllowCodeGenerationFromStrings callbacks --- // --- 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
/** /**
@@ -3046,6 +3056,9 @@ class V8EXPORT V8 { @@ -2816,6 +2826,9 @@ class V8EXPORT V8 {
/** Callback function for reporting failed access checks.*/ /** Callback function for reporting failed access checks.*/
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
@ -67,13 +66,13 @@ index c094d08..6baf2b2 100644
* Enables the host application to receive a notification before a * Enables the host application to receive a notification before a
* garbage collection. Allocations are not allowed in the * garbage collection. Allocations are not allowed in the
diff --git a/src/api.cc b/src/api.cc diff --git a/src/api.cc b/src/api.cc
index 526aa02..6f6297d 100644 index ff74efb..2436031 100644
--- a/src/api.cc --- a/src/api.cc
+++ b/src/api.cc +++ b/src/api.cc
@@ -1464,6 +1464,17 @@ void ObjectTemplate::SetHasExternalResource(bool value) @@ -1321,6 +1321,16 @@ void ObjectTemplate::SetHasExternalResource(bool value)
}
} }
+void ObjectTemplate::MarkAsUseUserObjectComparison() +void ObjectTemplate::MarkAsUseUserObjectComparison()
+{ +{
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
@ -84,15 +83,13 @@ index 526aa02..6f6297d 100644
+ EnsureConstructor(this); + EnsureConstructor(this);
+ Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1)); + Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1));
+} +}
+
// --- S c r i p t D a t a --- // --- S c r i p t D a t a ---
@@ -4632,6 +4642,15 @@ void V8::SetFailedAccessCheckCallbackFunction(
@@ -5106,6 +5117,17 @@ void V8::SetFailedAccessCheckCallbackFunction(
isolate->SetFailedAccessCheckCallback(callback); isolate->SetFailedAccessCheckCallback(callback);
} }
+
+void V8::SetUserObjectComparisonCallbackFunction( +void V8::SetUserObjectComparisonCallbackFunction(
+ UserObjectComparisonCallback callback) { + UserObjectComparisonCallback callback) {
+ i::Isolate* isolate = i::Isolate::Current(); + i::Isolate* isolate = i::Isolate::Current();
@ -101,16 +98,15 @@ index 526aa02..6f6297d 100644
+ } + }
+ isolate->SetUserObjectComparisonCallback(callback); + isolate->SetUserObjectComparisonCallback(callback);
+} +}
+
+ +
void V8::AddObjectGroup(Persistent<Value>* objects, void V8::AddObjectGroup(Persistent<Value>* objects,
size_t length, size_t length,
RetainedObjectInfo* info) { RetainedObjectInfo* info) {
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 00ac676..a67b3a0 100644 index a2626bf..749c9be 100644
--- a/src/arm/code-stubs-arm.cc --- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc
@@ -1494,6 +1494,37 @@ void CompareStub::Generate(MacroAssembler* masm) { @@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so // 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. // it is certain that at least one operand isn't a smi.
@ -126,12 +122,12 @@ index 00ac676..a67b3a0 100644
+ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE); + __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
+ __ b(ne, &not_user_equal); + __ b(ne, &not_user_equal);
+ +
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset)); + __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); + __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); + __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &user_equal); + __ b(eq, &user_equal);
+ +
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset)); + __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset));
+ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison)); + __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison)); + __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(ne, &not_user_equal); + __ b(ne, &not_user_equal);
@ -143,26 +139,25 @@ index 00ac676..a67b3a0 100644
+ +
+ __ bind(&not_user_equal); + __ bind(&not_user_equal);
+ } + }
+
+ +
// Handle the case where the objects are identical. Either returns the answer // 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. // or goes to slow. Only falls through if the objects were not identical.
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
@@ -6544,10 +6575,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { @@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ and_(r2, r1, Operand(r0)); __ tst(r2, Operand(kSmiTagMask));
__ JumpIfSmi(r2, &miss); __ b(eq, &miss);
- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); - __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
+ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE); + __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss); __ b(ne, &miss);
- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); - __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset)); + __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); + __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); + __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss); + __ b(eq, &miss);
+ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE); + __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss); __ b(ne, &miss);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset)); + __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison)); + __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison)); + __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss); + __ b(eq, &miss);
@ -170,10 +165,10 @@ index 00ac676..a67b3a0 100644
ASSERT(GetCondition() == eq); ASSERT(GetCondition() == eq);
__ sub(r0, r0, Operand(r1)); __ sub(r0, r0, Operand(r1));
diff --git a/src/factory.cc b/src/factory.cc diff --git a/src/factory.cc b/src/factory.cc
index e3cccae..96d3458 100644 index d530a75..6f8c7de 100644
--- a/src/factory.cc --- a/src/factory.cc
+++ b/src/factory.cc +++ b/src/factory.cc
@@ -1120,6 +1120,7 @@ Handle<JSFunction> Factory::CreateApiFunction( @@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
int internal_field_count = 0; int internal_field_count = 0;
bool has_external_resource = false; bool has_external_resource = false;
@ -181,7 +176,7 @@ index e3cccae..96d3458 100644
if (!obj->instance_template()->IsUndefined()) { if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo> instance_template =
@@ -1129,6 +1130,8 @@ Handle<JSFunction> Factory::CreateApiFunction( @@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
Smi::cast(instance_template->internal_field_count())->value(); Smi::cast(instance_template->internal_field_count())->value();
has_external_resource = has_external_resource =
!instance_template->has_external_resource()->IsUndefined(); !instance_template->has_external_resource()->IsUndefined();
@ -190,7 +185,7 @@ index e3cccae..96d3458 100644
} }
int instance_size = kPointerSize * internal_field_count; int instance_size = kPointerSize * internal_field_count;
@@ -1173,6 +1176,11 @@ Handle<JSFunction> Factory::CreateApiFunction( @@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
map->set_has_external_resource(true); map->set_has_external_resource(true);
} }
@ -203,15 +198,15 @@ index e3cccae..96d3458 100644
if (obj->undetectable()) { if (obj->undetectable()) {
map->set_is_undetectable(); map->set_is_undetectable();
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 6cc80d3..cabf78f 100644 index afa599e..0964ab9 100644
--- a/src/ia32/code-stubs-ia32.cc --- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc
@@ -3931,6 +3931,39 @@ void CompareStub::Generate(MacroAssembler* masm) { @@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so __ Assert(not_zero, "Unexpected smi operands.");
// it is certain that at least one operand isn't a smi. }
+ { + {
+ Label not_user_equal, user_equal; + NearLabel not_user_equal, user_equal;
+ __ test(eax, Immediate(kSmiTagMask)); + __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &not_user_equal); + __ j(zero, &not_user_equal);
+ __ test(edx, Immediate(kSmiTagMask)); + __ test(edx, Immediate(kSmiTagMask));
@ -223,10 +218,10 @@ index 6cc80d3..cabf78f 100644
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); + __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &not_user_equal); + __ j(not_equal, &not_user_equal);
+ +
+ __ test_b(FieldOperand(ebx, Map::kBitField2Offset), + __ test_b(FieldOperand(ebx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison); + 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal); + __ j(not_zero, &user_equal);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset), + __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison); + 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal); + __ j(not_zero, &user_equal);
+ +
@ -243,64 +238,40 @@ index 6cc80d3..cabf78f 100644
+ __ bind(&not_user_equal); + __ bind(&not_user_equal);
+ } + }
+ +
// Identical objects can be compared fast, but there are some tricky cases +
// for NaN and undefined. // 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.
@@ -6409,8 +6442,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear); __ j(not_equal, &miss, not_taken);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset), + __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison); + 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear); + __ j(not_zero, &miss);
__ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear); __ j(not_equal, &miss, not_taken);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset), + __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
+ 1 << Map::kUseUserObjectComparison); + 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear); + __ j(not_zero, &miss);
ASSERT(GetCondition() == equal); ASSERT(GetCondition() == equal);
__ sub(eax, edx); __ sub(eax, Operand(edx));
diff --git a/src/isolate.cc b/src/isolate.cc
index 951f428..6a86bf1 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -96,6 +96,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;
}
@@ -717,6 +718,12 @@ 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/isolate.h b/src/isolate.h diff --git a/src/isolate.h b/src/isolate.h
index 01ab04e..06ef22d 100644 index 35ffcb4..8130397 100644
--- a/src/isolate.h --- a/src/isolate.h
+++ b/src/isolate.h +++ b/src/isolate.h
@@ -255,6 +255,9 @@ class ThreadLocalTop BASE_EMBEDDED { @@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED {
// Call back function to report unsafe JS accesses. // Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_; v8::FailedAccessCheckCallback failed_access_check_callback_;
+ // Call back function for user object comparisons + // Call back function for user object comparisons
+ v8::UserObjectComparisonCallback user_object_comparison_callback_; + v8::UserObjectComparisonCallback user_object_comparison_callback_;
+ +
// Whether out of memory exceptions should be ignored. private:
bool ignore_out_of_memory_; void InitializeInternal();
@@ -701,6 +704,11 @@ class Isolate { @@ -699,6 +702,11 @@ class Isolate {
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback); void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
@ -313,116 +284,63 @@ index 01ab04e..06ef22d 100644
// of Throw() as its return value. // of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL); Failure* Throw(Object* exception, MessageLocation* location = NULL);
diff --git a/src/objects-inl.h b/src/objects-inl.h diff --git a/src/objects-inl.h b/src/objects-inl.h
index 375df0f..4657482 100644 index 1c7f83e..1765441 100644
--- a/src/objects-inl.h --- a/src/objects-inl.h
+++ b/src/objects-inl.h +++ b/src/objects-inl.h
@@ -2859,14 +2859,14 @@ bool Map::is_extensible() { @@ -2552,6 +2552,19 @@ bool Map::has_external_resource()
void Map::set_attached_to_shared_function_info(bool value) {
if (value) {
- set_bit_field2(bit_field2() | (1 << kAttachedToSharedFunctionInfo));
+ set_bit_field3(bit_field3() | (1 << kAttachedToSharedFunctionInfo));
} else {
- set_bit_field2(bit_field2() & ~(1 << kAttachedToSharedFunctionInfo));
+ set_bit_field3(bit_field3() & ~(1 << kAttachedToSharedFunctionInfo));
}
}
bool Map::attached_to_shared_function_info() {
- return ((1 << kAttachedToSharedFunctionInfo) & bit_field2()) != 0;
+ return ((1 << kAttachedToSharedFunctionInfo) & bit_field3()) != 0;
}
@@ -2896,6 +2896,19 @@ bool Map::has_external_resource()
} }
+void Map::set_use_user_object_comparison(bool value) { +void Map::set_use_user_object_comparison(bool value) {
+ if (value) { + if (value) {
+ set_bit_field2(bit_field2() | (1 << kUseUserObjectComparison)); + set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison));
+ } else { + } else {
+ set_bit_field2(bit_field2() & ~(1 << kUseUserObjectComparison)); + set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison));
+ } + }
+} +}
+ +
+bool Map::use_user_object_comparison() { +bool Map::use_user_object_comparison() {
+ return ((1 << kUseUserObjectComparison) & bit_field2()) != 0; + return ((1 << kUseUserObjectComparison) & bit_field3()) != 0;
+} +}
+ +
+ +
void Map::set_named_interceptor_is_fallback(bool value) void Map::set_named_interceptor_is_fallback(bool value)
{ {
if (value) { if (value) {
@@ -3429,6 +3442,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, @@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset) kInternalFieldCountOffset)
ACCESSORS(ObjectTemplateInfo, has_external_resource, Object, ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
kHasExternalResourceOffset) kHasExternalResourceOffset)
+ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object, +ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
+ kUseUserObjectComparisonOffset) + kUseUserObjectComparisonOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset) ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset) ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
diff --git a/src/objects.cc b/src/objects.cc
index 8e1773f..28e6d79 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -7159,8 +7159,8 @@ void SharedFunctionInfo::DetachInitialMap() {
Map* map = reinterpret_cast<Map*>(initial_map());
// Make the map remember to restore the link if it survives the GC.
- map->set_bit_field2(
- map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field3(
+ map->bit_field3() | (1 << Map::kAttachedToSharedFunctionInfo));
// Undo state changes made by StartInobjectTracking (except the
// construction_count). This way if the initial map does not survive the GC
@@ -7180,8 +7180,8 @@ void SharedFunctionInfo::DetachInitialMap() {
// Called from GC, hence reinterpret_cast and unchecked accessors.
void SharedFunctionInfo::AttachInitialMap(Map* map) {
- map->set_bit_field2(
- map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field3(
+ map->bit_field3() & ~(1 << Map::kAttachedToSharedFunctionInfo));
// Resume inobject slack tracking.
set_initial_map(map);
diff --git a/src/objects.h b/src/objects.h diff --git a/src/objects.h b/src/objects.h
index 71895be..881c24e 100644 index edbc47a..e75e9f1 100644
--- a/src/objects.h --- a/src/objects.h
+++ b/src/objects.h +++ b/src/objects.h
@@ -4084,6 +4084,11 @@ class Map: public HeapObject { @@ -3724,6 +3724,11 @@ class Map: public HeapObject {
inline void set_has_external_resource(bool value); inline void set_has_external_resource(bool value);
inline bool has_external_resource(); inline bool has_external_resource();
+
+ // Tells whether the user object comparison callback should be used for + // Tells whether the user object comparison callback should be used for
+ // comparisons involving this object + // comparisons involving this object
+ inline void set_use_user_object_comparison(bool value); + inline void set_use_user_object_comparison(bool value);
+ inline bool use_user_object_comparison(); + inline bool use_user_object_comparison();
+
// [prototype]: implicit prototype object. // Whether the named interceptor is a fallback interceptor or not
DECL_ACCESSORS(prototype, Object) inline void set_named_interceptor_is_fallback(bool value);
@@ -3922,6 +3927,7 @@ class Map: public HeapObject {
@@ -4303,7 +4308,7 @@ class Map: public HeapObject { // Bit positions for bit field 3
static const int kIsExtensible = 0; static const int kNamedInterceptorIsFallback = 0;
static const int kFunctionWithPrototype = 1; static const int kHasExternalResource = 1;
static const int kStringWrapperSafeForDefaultValueOf = 2; + static const int kUseUserObjectComparison = 2;
- static const int kAttachedToSharedFunctionInfo = 3;
+ static const int kUseUserObjectComparison = 3;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
// storing ElementKind.
static const int kElementsKindShift = 4;
@@ -4322,6 +4327,7 @@ class Map: public HeapObject {
static const int kIsShared = 0;
static const int kNamedInterceptorIsFallback = 1;
static const int kHasInstanceCallHandler = 2;
+ static const int kAttachedToSharedFunctionInfo = 3;
// Layout of the default cache. It holds alternating name and code objects. // Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2; static const int kCodeCacheEntrySize = 2;
@@ -7306,6 +7312,7 @@ class ObjectTemplateInfo: public TemplateInfo { @@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo {
DECL_ACCESSORS(constructor, Object) DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object) DECL_ACCESSORS(internal_field_count, Object)
DECL_ACCESSORS(has_external_resource, Object) DECL_ACCESSORS(has_external_resource, Object)
@ -430,7 +348,7 @@ index 71895be..881c24e 100644
static inline ObjectTemplateInfo* cast(Object* obj); static inline ObjectTemplateInfo* cast(Object* obj);
@@ -7323,7 +7330,8 @@ class ObjectTemplateInfo: public TemplateInfo { @@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kInternalFieldCountOffset = static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize; kConstructorOffset + kPointerSize;
static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize; static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
@ -441,10 +359,10 @@ index 71895be..881c24e 100644
diff --git a/src/runtime.cc b/src/runtime.cc diff --git a/src/runtime.cc b/src/runtime.cc
index 0388a77..24b3de0 100644 index c13f92d..b50de80 100644
--- a/src/runtime.cc --- a/src/runtime.cc
+++ b/src/runtime.cc +++ b/src/runtime.cc
@@ -7008,6 +7008,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { @@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
} }
@ -475,10 +393,10 @@ index 0388a77..24b3de0 100644
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
diff --git a/src/runtime.h b/src/runtime.h diff --git a/src/runtime.h b/src/runtime.h
index 284f723..5d6bf5e 100644 index 5e97173..0d754f9 100644
--- a/src/runtime.h --- a/src/runtime.h
+++ b/src/runtime.h +++ b/src/runtime.h
@@ -157,6 +157,7 @@ namespace internal { @@ -146,6 +146,7 @@ namespace internal {
/* Comparisons */ \ /* Comparisons */ \
F(NumberEquals, 2, 1) \ F(NumberEquals, 2, 1) \
F(StringEquals, 2, 1) \ F(StringEquals, 2, 1) \
@ -486,16 +404,39 @@ index 284f723..5d6bf5e 100644
\ \
F(NumberCompare, 3, 1) \ F(NumberCompare, 3, 1) \
F(SmiLexicographicCompare, 2, 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 diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 6ab12fc..3be2c4b 100644 index d923494..10b9b56 100644
--- a/src/x64/code-stubs-x64.cc --- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc
@@ -3005,6 +3005,37 @@ void CompareStub::Generate(MacroAssembler* masm) { @@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so __ bind(&ok);
// it is certain that at least one operand isn't a smi. }
+ { + {
+ Label not_user_equal, user_equal; + NearLabel not_user_equal, user_equal;
+ __ JumpIfSmi(rax, &not_user_equal); + __ JumpIfSmi(rax, &not_user_equal);
+ __ JumpIfSmi(rdx, &not_user_equal); + __ JumpIfSmi(rdx, &not_user_equal);
+ +
@ -505,10 +446,10 @@ index 6ab12fc..3be2c4b 100644
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); + __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &not_user_equal); + __ j(not_equal, &not_user_equal);
+ +
+ __ testb(FieldOperand(rbx, Map::kBitField2Offset), + __ testb(FieldOperand(rbx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison)); + Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal); + __ j(not_zero, &user_equal);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset), + __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison)); + Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal); + __ j(not_zero, &user_equal);
+ +
@ -525,21 +466,21 @@ index 6ab12fc..3be2c4b 100644
+ __ bind(&not_user_equal); + __ bind(&not_user_equal);
+ } + }
+ +
// Two identical objects are equal unless they are both NaN or undefined. // The compare stub returns a positive, negative, or zero 64-bit integer
{ // value in rax, corresponding to result of comparing the two inputs.
Label not_identical; // NOTICE! This code is only reached after a smi-fast-case check, so
@@ -5337,8 +5368,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) { @@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear); __ j(not_equal, &miss, not_taken);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset), + __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison)); + Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear); + __ j(not_zero, &miss);
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear); __ j(not_equal, &miss, not_taken);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset), + __ testb(FieldOperand(rcx, Map::kBitField3Offset),
+ Immediate(1 << Map::kUseUserObjectComparison)); + Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear); + __ j(not_zero, &miss);
ASSERT(GetCondition() == equal); ASSERT(GetCondition() == equal);
__ subq(rax, rdx); __ subq(rax, rdx);

View File

@ -0,0 +1,287 @@
From 15ce2909579aef8c8f6b0c2c07fdebbaf0f4d611 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/16] 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 7544deb..277153e 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1758,6 +1758,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.4.4

View File

@ -0,0 +1,398 @@
From 3ba270e3b93d292dc53a675a21479bdb0b50bbbe 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/16] 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 277153e..18527e1 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1766,6 +1766,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.4.4

View File

@ -1,7 +1,7 @@
From 3c304e3712ebf9f0df0b544032f0f83945d08028 Mon Sep 17 00:00:00 2001 From 5f3e5dd6901b54707ea4f868d8fa7317c4ab3852 Mon Sep 17 00:00:00 2001
From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com> From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
Date: Tue, 7 Dec 2010 11:56:42 +0100 Date: Tue, 7 Dec 2010 11:56:42 +0100
Subject: [PATCH 08/11] QtScript/V8: Add new v8 api to check if a value is an Subject: [PATCH 11/16] QtScript/V8: Add new v8 api to check if a value is an
error. error.
New function v8::Value::IsError was created. New function v8::Value::IsError was created.
@ -15,10 +15,10 @@ research.
3 files changed, 12 insertions(+), 0 deletions(-) 3 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index 229ddbd..d995e54 100644 index 18527e1..43e00f5 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -967,6 +967,11 @@ class Value : public Data { @@ -937,6 +937,11 @@ class Value : public Data {
*/ */
V8EXPORT bool IsRegExp() const; V8EXPORT bool IsRegExp() const;
@ -31,10 +31,10 @@ index 229ddbd..d995e54 100644
V8EXPORT Local<Number> ToNumber() const; V8EXPORT Local<Number> ToNumber() const;
V8EXPORT Local<String> ToString() const; V8EXPORT Local<String> ToString() const;
diff --git a/src/api.cc b/src/api.cc diff --git a/src/api.cc b/src/api.cc
index 6f6297d..c21af67 100644 index 1a585d6..bd435eb 100644
--- a/src/api.cc --- a/src/api.cc
+++ b/src/api.cc +++ b/src/api.cc
@@ -2316,6 +2316,12 @@ bool Value::IsRegExp() const { @@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const {
return obj->IsJSRegExp(); return obj->IsJSRegExp();
} }
@ -48,10 +48,10 @@ index 6f6297d..c21af67 100644
Local<String> Value::ToString() const { Local<String> Value::ToString() const {
i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::Object> obj = Utils::OpenHandle(this);
diff --git a/src/heap.h b/src/heap.h diff --git a/src/heap.h b/src/heap.h
index bab4c63..ad83b70 100644 index 8cbf378..db90bb9 100644
--- a/src/heap.h --- a/src/heap.h
+++ b/src/heap.h +++ b/src/heap.h
@@ -188,6 +188,7 @@ inline Heap* _inline_get_heap_(); @@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_();
V(string_symbol, "string") \ V(string_symbol, "string") \
V(String_symbol, "String") \ V(String_symbol, "String") \
V(Date_symbol, "Date") \ V(Date_symbol, "Date") \

View File

@ -0,0 +1,116 @@
From a338d96fe138fbffd4b45c7d13a54e068daa6e12 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/16] 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 43e00f5..5e1ce50 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1764,6 +1764,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.4.4

View File

@ -1,7 +1,7 @@
From 8796bc9571db9f7049c96a9829281fedc54f8f38 Mon Sep 17 00:00:00 2001 From c36be227e9d7952a1952caa529c78ecdc376bd55 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Thu, 25 Aug 2011 11:09:58 +1000 Date: Thu, 25 Aug 2011 11:09:58 +1000
Subject: [PATCH 10/11] Remove execute flag from v8-debug.h Subject: [PATCH 13/16] Remove execute flag from v8-debug.h
--- ---
0 files changed, 0 insertions(+), 0 deletions(-) 0 files changed, 0 insertions(+), 0 deletions(-)

View File

@ -1,7 +1,7 @@
From 234a7bf490c4870f2d015221bb5158de4933519c Mon Sep 17 00:00:00 2001 From ed5cc903d70f73780e5985e7d2de33f6b8d86402 Mon Sep 17 00:00:00 2001
From: Kent Hansen <kent.hansen@nokia.com> From: Kent Hansen <kent.hansen@nokia.com>
Date: Fri, 2 Sep 2011 12:03:09 +0200 Date: Fri, 2 Sep 2011 12:03:09 +0200
Subject: [PATCH 09/11] Fix deprecated Python code Subject: [PATCH 14/16] Fix deprecated Python code
Needed to make the scripts run on Python 3, which is the Needed to make the scripts run on Python 3, which is the
default python interpreter on some newer distros. default python interpreter on some newer distros.
@ -13,10 +13,10 @@ Patch from http://code.google.com/p/v8/issues/detail?id=1391
2 files changed, 3 insertions(+), 3 deletions(-) 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/js2c.py b/tools/js2c.py diff --git a/tools/js2c.py b/tools/js2c.py
index a2ea8ea..fe6a72e 100644 index 2da132f..d13d53d 100755
--- a/tools/js2c.py --- a/tools/js2c.py
+++ b/tools/js2c.py +++ b/tools/js2c.py
@@ -194,14 +194,14 @@ def ReadMacros(lines): @@ -187,14 +187,14 @@ def ReadMacros(lines):
macro_match = MACRO_PATTERN.match(line) macro_match = MACRO_PATTERN.match(line)
if macro_match: if macro_match:
name = macro_match.group(1) name = macro_match.group(1)

View File

@ -1,7 +1,7 @@
From a1572a979803dda787be4a7095d5c37e926443a7 Mon Sep 17 00:00:00 2001 From 523f03f03b1ac16d272a13389f8a5654d9ff12e6 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com> From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Fri, 9 Sep 2011 14:16:12 +1000 Date: Fri, 9 Sep 2011 14:16:12 +1000
Subject: [PATCH 07/11] Allow a script to be flagged as "native" Subject: [PATCH 15/16] Allow a script to be flagged as "native"
Native scripts do not appear in backtraces, or in the source and Native scripts do not appear in backtraces, or in the source and
line number when exceptions are thrown from within them. This is line number when exceptions are thrown from within them. This is
@ -13,10 +13,10 @@ still have it appear sensibly to the user.
2 files changed, 4 insertions(+), 3 deletions(-) 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/v8.h b/include/v8.h diff --git a/include/v8.h b/include/v8.h
index 6baf2b2..229ddbd 100644 index 5e1ce50..a2d61d1 100644
--- a/include/v8.h --- a/include/v8.h
+++ b/include/v8.h +++ b/include/v8.h
@@ -588,8 +588,9 @@ class ScriptOrigin { @@ -578,8 +578,9 @@ class ScriptOrigin {
class V8EXPORT Script { class V8EXPORT Script {
public: public:
enum CompileFlags { enum CompileFlags {
@ -29,10 +29,10 @@ index 6baf2b2..229ddbd 100644
/** /**
diff --git a/src/compiler.cc b/src/compiler.cc diff --git a/src/compiler.cc b/src/compiler.cc
index 596df4a..b760b71 100644 index d2191b9..873018c 100755
--- a/src/compiler.cc --- a/src/compiler.cc
+++ b/src/compiler.cc +++ b/src/compiler.cc
@@ -501,7 +501,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, @@ -507,7 +507,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.
Handle<Script> script = FACTORY->NewScript(source); Handle<Script> script = FACTORY->NewScript(source);

View File

@ -0,0 +1,61 @@
From 8f15248619bb3bf49473dc3ede8a4e631bd5d199 Mon Sep 17 00:00:00 2001
From: Aaron Kennedy <aaron.kennedy@nokia.com>
Date: Tue, 4 Oct 2011 14:22:54 +1000
Subject: [PATCH 16/16] Move external resource to the last hidden field
---
src/objects-inl.h | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 1765441..c02e037 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1398,7 +1398,7 @@ int JSObject::GetInternalFieldCount() {
int JSObject::GetInternalFieldOffset(int index) {
ASSERT(index < GetInternalFieldCount() && index >= 0);
- return GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0));
+ return GetHeaderSize() + (kPointerSize * index);
}
@@ -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 + map()->has_external_resource()?1:0)));
+ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index));
}
@@ -1416,7 +1416,7 @@ 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 + map()->has_external_resource()?1:0));
+ int offset = GetHeaderSize() + (kPointerSize * index);
WRITE_FIELD(this, offset, value);
WRITE_BARRIER(this, offset);
}
@@ -1424,7 +1424,7 @@ void JSObject::SetInternalField(int index, Object* value) {
void JSObject::SetExternalResourceObject(Object *value) {
ASSERT(map()->has_external_resource());
- int offset = GetHeaderSize();
+ int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
WRITE_FIELD(this, offset, value);
WRITE_BARRIER(this, offset);
}
@@ -1432,7 +1432,7 @@ void JSObject::SetExternalResourceObject(Object *value) {
Object *JSObject::GetExternalResourceObject() {
if (map()->has_external_resource()) {
- return READ_FIELD(this, GetHeaderSize());
+ return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
} else {
return GetHeap()->undefined_value();
}
--
1.7.4.4

View File

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

View File

@ -72,10 +72,10 @@ SOURCES += \
$$V8SRC/disassembler.cc \ $$V8SRC/disassembler.cc \
$$V8SRC/diy-fp.cc \ $$V8SRC/diy-fp.cc \
$$V8SRC/dtoa.cc \ $$V8SRC/dtoa.cc \
$$V8SRC/elements.cc \
$$V8SRC/execution.cc \ $$V8SRC/execution.cc \
$$V8SRC/factory.cc \ $$V8SRC/factory.cc \
$$V8SRC/flags.cc \ $$V8SRC/flags.cc \
$$V8SRC/frame-element.cc \
$$V8SRC/frames.cc \ $$V8SRC/frames.cc \
$$V8SRC/full-codegen.cc \ $$V8SRC/full-codegen.cc \
$$V8SRC/func-name-inferrer.cc \ $$V8SRC/func-name-inferrer.cc \
@ -90,7 +90,6 @@ SOURCES += \
$$V8SRC/hydrogen.cc \ $$V8SRC/hydrogen.cc \
$$V8SRC/hydrogen-instructions.cc \ $$V8SRC/hydrogen-instructions.cc \
$$V8SRC/ic.cc \ $$V8SRC/ic.cc \
$$V8SRC/incremental-marking.cc \
$$V8SRC/inspector.cc \ $$V8SRC/inspector.cc \
$$V8SRC/interpreter-irregexp.cc \ $$V8SRC/interpreter-irregexp.cc \
$$V8SRC/isolate.cc \ $$V8SRC/isolate.cc \
@ -118,8 +117,8 @@ SOURCES += \
$$V8SRC/runtime.cc \ $$V8SRC/runtime.cc \
$$V8SRC/runtime-profiler.cc \ $$V8SRC/runtime-profiler.cc \
$$V8SRC/safepoint-table.cc \ $$V8SRC/safepoint-table.cc \
$$V8SRC/scanner-base.cc \
$$V8SRC/scanner.cc \ $$V8SRC/scanner.cc \
$$V8SRC/scanner-character-streams.cc \
$$V8SRC/scopeinfo.cc \ $$V8SRC/scopeinfo.cc \
$$V8SRC/scopes.cc \ $$V8SRC/scopes.cc \
$$V8SRC/serialize.cc \ $$V8SRC/serialize.cc \
@ -130,17 +129,15 @@ SOURCES += \
$$V8SRC/strtod.cc \ $$V8SRC/strtod.cc \
$$V8SRC/stub-cache.cc \ $$V8SRC/stub-cache.cc \
$$V8SRC/token.cc \ $$V8SRC/token.cc \
$$V8SRC/top.cc \
$$V8SRC/type-info.cc \ $$V8SRC/type-info.cc \
$$V8SRC/unicode.cc \ $$V8SRC/unicode.cc \
$$V8SRC/utils.cc \ $$V8SRC/utils.cc \
$$V8SRC/v8-counters.cc \ $$V8SRC/v8-counters.cc \
$$V8SRC/v8.cc \ $$V8SRC/v8.cc \
$$V8SRC/v8conversions.cc \
$$V8SRC/v8threads.cc \ $$V8SRC/v8threads.cc \
$$V8SRC/v8utils.cc \
$$V8SRC/variables.cc \ $$V8SRC/variables.cc \
$$V8SRC/version.cc \ $$V8SRC/version.cc \
$$V8SRC/store-buffer.cc \
$$V8SRC/zone.cc \ $$V8SRC/zone.cc \
$$V8SRC/extensions/gc-extension.cc \ $$V8SRC/extensions/gc-extension.cc \
$$V8SRC/extensions/externalize-string-extension.cc $$V8SRC/extensions/externalize-string-extension.cc
@ -261,11 +258,7 @@ V8_LIBRARY_FILES = \
$$V8SRC/mirror-debugger.js \ $$V8SRC/mirror-debugger.js \
$$V8SRC/debug-debugger.js $$V8SRC/debug-debugger.js
V8_EXPERIMENTAL_LIBRARY_FILES = \ v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp $$V8_GENERATED_SOURCES_DIR/libraries-empty.cpp CORE
$$V8SRC/proxy.js \
$$V8SRC/weakmap.js
v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp CORE off
v8_js2c.commands += $$V8SRC/macros.py ${QMAKE_FILE_IN} v8_js2c.commands += $$V8SRC/macros.py ${QMAKE_FILE_IN}
v8_js2c.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp v8_js2c.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp
v8_js2c.input = V8_LIBRARY_FILES v8_js2c.input = V8_LIBRARY_FILES
@ -275,15 +268,4 @@ v8_js2c.depends = $$V8DIR/tools/js2c.py $$V8SRC/macros.py
v8_js2c.CONFIG += combine v8_js2c.CONFIG += combine
v8_js2c.name = generating[v8] ${QMAKE_FILE_IN} v8_js2c.name = generating[v8] ${QMAKE_FILE_IN}
silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands
QMAKE_EXTRA_COMPILERS += v8_js2c
v8_js2c_experimental.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/experimental-libraries.cpp EXPERIMENTAL off
v8_js2c_experimental.commands += $$V8SRC/macros.py ${QMAKE_FILE_IN}
v8_js2c_experimental.output = $$V8_GENERATED_SOURCES_DIR/experimental-libraries.cpp
v8_js2c_experimental.input = V8_EXPERIMENTAL_LIBRARY_FILES
v8_js2c_experimental.variable_out = SOURCES
v8_js2c_experimental.dependency_type = TYPE_C
v8_js2c_experimental.depends = $$V8DIR/tools/js2c.py $$V8SRC/macros.py
v8_js2c_experimental.CONFIG += combine
v8_js2c_experimental.name = generating[v8] ${QMAKE_FILE_IN}
QMAKE_EXTRA_COMPILERS += v8_js2c v8_js2c_experimental

View File

@ -57,7 +57,6 @@ private slots:
void eval(); void eval();
void evalwithinwith(); void evalwithinwith();
void userobjectcompare(); void userobjectcompare();
void externalteardown();
}; };
void tst_v8::eval() void tst_v8::eval()
@ -75,11 +74,6 @@ void tst_v8::userobjectcompare()
QVERIFY(v8test_userobjectcompare()); QVERIFY(v8test_userobjectcompare());
} }
void tst_v8::externalteardown()
{
QVERIFY(v8test_externalteardown());
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
V8::SetFlagsFromCommandLine(&argc, argv, true); V8::SetFlagsFromCommandLine(&argc, argv, true);

View File

@ -45,8 +45,6 @@
#define RUN_TEST(testname) { \ #define RUN_TEST(testname) { \
if (!v8test_ ## testname()) \ if (!v8test_ ## testname()) \
printf ("Test %s FAILED\n", # testname); \ printf ("Test %s FAILED\n", # testname); \
else \
printf ("Test %s PASS\n", # testname); \
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -56,7 +54,6 @@ int main(int argc, char *argv[])
RUN_TEST(eval); RUN_TEST(eval);
RUN_TEST(evalwithinwith); RUN_TEST(evalwithinwith);
RUN_TEST(userobjectcompare); RUN_TEST(userobjectcompare);
RUN_TEST(externalteardown);
return -1; return -1;
} }

View File

@ -54,59 +54,6 @@ using namespace v8;
} \ } \
} }
struct MyStringResource : public String::ExternalAsciiStringResource
{
static bool wasDestroyed;
virtual ~MyStringResource() { wasDestroyed = true; }
virtual const char* data() const { return "v8test"; }
virtual size_t length() const { return 6; }
};
bool MyStringResource::wasDestroyed = false;
struct MyResource : public Object::ExternalResource
{
static bool wasDestroyed;
virtual ~MyResource() { wasDestroyed = true; }
};
bool MyResource::wasDestroyed = false;
bool v8test_externalteardown()
{
BEGINTEST();
Isolate *isolate = v8::Isolate::New();
isolate->Enter();
{
HandleScope handle_scope;
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);
Local<String> str = String::NewExternal(new MyStringResource);
Local<FunctionTemplate> ft = FunctionTemplate::New();
ft->InstanceTemplate()->SetHasExternalResource(true);
Local<Object> obj = ft->GetFunction()->NewInstance();
obj->SetExternalResource(new MyResource);
context.Dispose();
}
// while (!v8::V8::IdleNotification()) ;
isolate->Exit();
isolate->Dispose();
// ExternalString resources aren't guaranteed to be freed by v8 at this
// point. Uncommenting the IdleNotification() line above helps.
// VERIFY(MyStringResource::wasDestroyed);
VERIFY(MyResource::wasDestroyed);
cleanup:
ENDTEST();
}
bool v8test_eval() bool v8test_eval()
{ {

View File

@ -51,7 +51,6 @@
bool v8test_eval(); bool v8test_eval();
bool v8test_evalwithinwith(); bool v8test_evalwithinwith();
bool v8test_userobjectcompare(); bool v8test_userobjectcompare();
bool v8test_externalteardown();
#endif // V8TEST_H #endif // V8TEST_H