Update V8
Change-Id: I7a9da7dbb2116a441788407d60ed10155cded941 Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
This commit is contained in:
parent
4dc25c1f29
commit
7dc5973bf1
2
src/3rdparty/v8
vendored
2
src/3rdparty/v8
vendored
@ -1 +1 @@
|
||||
Subproject commit 8f15248619bb3bf49473dc3ede8a4e631bd5d199
|
||||
Subproject commit 9c0d93bfae724e29ef63456942d9ddca10ca5825
|
@ -1,25 +1,25 @@
|
||||
From 3dff2e903674d8ab5310d44281b57de36db659c9 Mon Sep 17 00:00:00 2001
|
||||
From b0b5bcfbda218aac8e797c19ff6f6de4052d972f Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Mon, 23 May 2011 15:47:20 +1000
|
||||
Subject: [PATCH 01/16] Add hashing and comparison methods to v8::String
|
||||
Date: Tue, 4 Oct 2011 15:04:21 +1000
|
||||
Subject: [PATCH 01/11] Add hashing and comparison methods to v8::String
|
||||
|
||||
This allows us to more rapidly search for a v8::String inside
|
||||
a hash of QStrings.
|
||||
This allows us to more rapidly search for a v8::String inside a hash
|
||||
of QStrings.
|
||||
---
|
||||
include/v8.h | 45 +++++++++++++++++++++++++++++++
|
||||
src/api.cc | 43 +++++++++++++++++++++++++++++
|
||||
include/v8.h | 45 +++++++++++++++++++++++++++++
|
||||
src/api.cc | 51 +++++++++++++++++++++++++++++++++
|
||||
src/heap-inl.h | 2 +
|
||||
src/heap.cc | 3 ++
|
||||
src/objects-inl.h | 1 +
|
||||
src/objects.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/objects.h | 15 +++++++++-
|
||||
7 files changed, 183 insertions(+), 3 deletions(-)
|
||||
src/objects.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/objects.h | 10 ++++++-
|
||||
7 files changed, 192 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index d15d024..be1ee71 100644
|
||||
index 73b7fbe..86ea70f 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -994,6 +994,49 @@ class String : public Primitive {
|
||||
@@ -1021,6 +1021,49 @@ class String : public Primitive {
|
||||
V8EXPORT int Utf8Length() const;
|
||||
|
||||
/**
|
||||
@ -69,29 +69,30 @@ index d15d024..be1ee71 100644
|
||||
* Write the contents of the string to an external buffer.
|
||||
* If no arguments are given, expects the buffer to be large
|
||||
* enough to hold the entire string and NULL terminator. Copies
|
||||
@@ -1023,6 +1066,8 @@ class String : public Primitive {
|
||||
HINT_MANY_WRITES_EXPECTED = 1
|
||||
@@ -1051,6 +1094,8 @@ class String : public Primitive {
|
||||
NO_NULL_TERMINATION = 2
|
||||
};
|
||||
|
||||
+ V8EXPORT uint16_t GetCharacter(int index);
|
||||
+
|
||||
// 16-bit character codes.
|
||||
V8EXPORT int Write(uint16_t* buffer,
|
||||
int start = 0,
|
||||
int length = -1,
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index a2373cd..381935b 100644
|
||||
index 7ae01d1..2d205fd 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -3284,6 +3284,49 @@ int String::Utf8Length() const {
|
||||
return str->Utf8Length();
|
||||
@@ -3652,6 +3652,57 @@ int String::Utf8Length() const {
|
||||
}
|
||||
|
||||
|
||||
+uint32_t String::Hash() const {
|
||||
+ i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
|
||||
+ return str->Hash();
|
||||
+}
|
||||
+
|
||||
+
|
||||
+String::CompleteHashData String::CompleteHash() const {
|
||||
+ i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData();
|
||||
@ -103,40 +104,47 @@ index a2373cd..381935b 100644
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+uint32_t String::ComputeHash(uint16_t *string, int length) {
|
||||
+ return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+uint32_t String::ComputeHash(char *string, int length) {
|
||||
+ return i::HashSequentialString<char>(string, length) >> i::String::kHashShift;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+uint16_t String::GetCharacter(int index)
|
||||
+{
|
||||
+ i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
+ return str->Get(index);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+bool String::Equals(uint16_t *string, int length) {
|
||||
+ i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
|
||||
+ return str->SlowEqualsExternal(string, length);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+bool String::Equals(char *string, int length)
|
||||
+{
|
||||
+ i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
|
||||
+ return str->SlowEqualsExternal(string, length);
|
||||
+}
|
||||
|
||||
+
|
||||
+
|
||||
int String::WriteUtf8(char* buffer,
|
||||
int capacity,
|
||||
int* nchars_ref,
|
||||
diff --git a/src/heap-inl.h b/src/heap-inl.h
|
||||
index 99737ed..f4fce7b 100644
|
||||
index 4bd893e..a4dfa5a 100644
|
||||
--- a/src/heap-inl.h
|
||||
+++ b/src/heap-inl.h
|
||||
@@ -93,6 +93,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
|
||||
@@ -105,6 +105,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
|
||||
String* answer = String::cast(result);
|
||||
answer->set_length(str.length());
|
||||
answer->set_hash_field(hash_field);
|
||||
@ -144,7 +152,7 @@ index 99737ed..f4fce7b 100644
|
||||
|
||||
ASSERT_EQ(size, answer->Size());
|
||||
|
||||
@@ -126,6 +127,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
|
||||
@@ -138,6 +139,7 @@ MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
|
||||
String* answer = String::cast(result);
|
||||
answer->set_length(str.length());
|
||||
answer->set_hash_field(hash_field);
|
||||
@ -153,18 +161,18 @@ index 99737ed..f4fce7b 100644
|
||||
ASSERT_EQ(size, answer->Size());
|
||||
|
||||
diff --git a/src/heap.cc b/src/heap.cc
|
||||
index 2b6c11f..930c97b 100644
|
||||
index 522861d..0dfd453 100644
|
||||
--- a/src/heap.cc
|
||||
+++ b/src/heap.cc
|
||||
@@ -3519,6 +3519,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
@@ -4061,6 +4061,7 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
String* answer = String::cast(result);
|
||||
answer->set_length(chars);
|
||||
answer->set_hash_field(hash_field);
|
||||
+ SeqString::cast(result)->set_symbol_id(0);
|
||||
+ SeqString::cast(answer)->set_symbol_id(0);
|
||||
|
||||
ASSERT_EQ(size, answer->Size());
|
||||
|
||||
@@ -3561,6 +3562,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
|
||||
@@ -4103,6 +4104,7 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
|
||||
HeapObject::cast(result)->set_map(ascii_string_map());
|
||||
String::cast(result)->set_length(length);
|
||||
String::cast(result)->set_hash_field(String::kEmptyHashField);
|
||||
@ -172,7 +180,7 @@ index 2b6c11f..930c97b 100644
|
||||
ASSERT_EQ(size, HeapObject::cast(result)->Size());
|
||||
return result;
|
||||
}
|
||||
@@ -3596,6 +3598,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length,
|
||||
@@ -4138,6 +4140,7 @@ MaybeObject* Heap::AllocateRawTwoByteString(int length,
|
||||
HeapObject::cast(result)->set_map(string_map());
|
||||
String::cast(result)->set_length(length);
|
||||
String::cast(result)->set_hash_field(String::kEmptyHashField);
|
||||
@ -181,11 +189,11 @@ index 2b6c11f..930c97b 100644
|
||||
return result;
|
||||
}
|
||||
diff --git a/src/objects-inl.h b/src/objects-inl.h
|
||||
index 65aec5d..c82080d 100644
|
||||
index baf271f..73d0ac9 100644
|
||||
--- a/src/objects-inl.h
|
||||
+++ b/src/objects-inl.h
|
||||
@@ -1924,6 +1924,7 @@ INT_ACCESSORS(ExternalArray, length, kLengthOffset)
|
||||
|
||||
@@ -2192,6 +2192,7 @@ SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
|
||||
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
|
||||
|
||||
SMI_ACCESSORS(String, length, kLengthOffset)
|
||||
+SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset)
|
||||
@ -193,13 +201,13 @@ index 65aec5d..c82080d 100644
|
||||
|
||||
uint32_t String::hash_field() {
|
||||
diff --git a/src/objects.cc b/src/objects.cc
|
||||
index df61956..dc4b260 100644
|
||||
index 45ae49d..fe5bf97 100644
|
||||
--- a/src/objects.cc
|
||||
+++ b/src/objects.cc
|
||||
@@ -5346,6 +5346,66 @@ static inline bool CompareStringContentsPartial(Isolate* isolate,
|
||||
}
|
||||
@@ -6242,6 +6242,71 @@ static inline bool CompareStringContentsPartial(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
+bool String::SlowEqualsExternal(uc16 *string, int length) {
|
||||
+ int len = this->length();
|
||||
+ if (len != length) return false;
|
||||
@ -212,13 +220,14 @@ index df61956..dc4b260 100644
|
||||
+ String* lhs = this->TryFlattenGetString();
|
||||
+
|
||||
+ if (lhs->IsFlat()) {
|
||||
+ String::FlatContent lhs_content = lhs->GetFlatContent();
|
||||
+ if (lhs->IsAsciiRepresentation()) {
|
||||
+ Vector<const char> vec1 = lhs->ToAsciiVector();
|
||||
+ Vector<const char> vec1 = lhs_content.ToAsciiVector();
|
||||
+ VectorIterator<char> buf1(vec1);
|
||||
+ VectorIterator<uc16> ib(string, length);
|
||||
+ return CompareStringContents(&buf1, &ib);
|
||||
+ } else {
|
||||
+ Vector<const uc16> vec1 = lhs->ToUC16Vector();
|
||||
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
|
||||
+ Vector<const uc16> vec2(string, length);
|
||||
+ return CompareRawStringContents(vec1, vec2);
|
||||
+ }
|
||||
@ -230,6 +239,7 @@ index df61956..dc4b260 100644
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
+bool String::SlowEqualsExternal(char *string, int length)
|
||||
+{
|
||||
+ int len = this->length();
|
||||
@ -249,10 +259,11 @@ index df61956..dc4b260 100644
|
||||
+ }
|
||||
+
|
||||
+ if (lhs->IsFlat()) {
|
||||
+ Vector<const uc16> vec1 = lhs->ToUC16Vector();
|
||||
+ VectorIterator<const uc16> buf1(vec1);
|
||||
+ VectorIterator<char> buf2(string, length);
|
||||
+ return CompareStringContents(&buf1, &buf2);
|
||||
+ String::FlatContent lhs_content = lhs->GetFlatContent();
|
||||
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
|
||||
+ VectorIterator<const uc16> buf1(vec1);
|
||||
+ VectorIterator<char> buf2(string, length);
|
||||
+ return CompareStringContents(&buf1, &buf2);
|
||||
+ } else {
|
||||
+ Isolate* isolate = GetIsolate();
|
||||
+ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
|
||||
@ -260,10 +271,12 @@ index df61956..dc4b260 100644
|
||||
+ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib);
|
||||
+ }
|
||||
+}
|
||||
|
||||
+
|
||||
+
|
||||
bool String::SlowEquals(String* other) {
|
||||
// Fast check: negative check with lengths.
|
||||
@@ -8655,9 +8715,24 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
|
||||
int len = length();
|
||||
@@ -10103,9 +10168,24 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> {
|
||||
|
||||
MaybeObject* AsObject() {
|
||||
if (hash_field_ == 0) Hash();
|
||||
@ -288,12 +301,12 @@ index df61956..dc4b260 100644
|
||||
+Atomic32 AsciiSymbolKey::next_symbol_id = 1;
|
||||
|
||||
|
||||
class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
|
||||
class SubStringAsciiSymbolKey : public HashTableKey {
|
||||
diff --git a/src/objects.h b/src/objects.h
|
||||
index e966b3d..6e26f57 100644
|
||||
index 5a1a4a3..eb4eb0e 100644
|
||||
--- a/src/objects.h
|
||||
+++ b/src/objects.h
|
||||
@@ -5359,6 +5359,9 @@ class String: public HeapObject {
|
||||
@@ -5952,6 +5952,9 @@ class String: public HeapObject {
|
||||
bool IsAsciiEqualTo(Vector<const char> str);
|
||||
bool IsTwoByteEqualTo(Vector<const uc16> str);
|
||||
|
||||
@ -303,42 +316,21 @@ index e966b3d..6e26f57 100644
|
||||
// Return a UTF8 representation of the string. The string is null
|
||||
// terminated but may optionally contain nulls. Length is returned
|
||||
// in length_output if length_output is not a null pointer The string
|
||||
@@ -5610,9 +5613,17 @@ class String: public HeapObject {
|
||||
class SeqString: public String {
|
||||
public:
|
||||
@@ -6207,8 +6210,13 @@ class SeqString: public String {
|
||||
// Casting.
|
||||
static inline SeqString* cast(Object* obj);
|
||||
|
||||
+ // Get and set the symbol id of the string
|
||||
+ inline int symbol_id();
|
||||
+ inline void set_symbol_id(int value);
|
||||
+
|
||||
// Casting.
|
||||
static inline SeqString* cast(Object* obj);
|
||||
|
||||
+ // Layout description.
|
||||
// Layout description.
|
||||
- static const int kHeaderSize = String::kSize;
|
||||
+ 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 {
|
||||
}
|
||||
+ static const int kHeaderSize = kSymbolIdOffset + kPointerSize;
|
||||
|
||||
// Layout description.
|
||||
- static const int kHeaderSize = String::kSize;
|
||||
+ static const int kHeaderSize = SeqString::kSize;
|
||||
static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize);
|
||||
|
||||
// Maximal memory usage for a single sequential ASCII string.
|
||||
@@ -5701,7 +5712,7 @@ class SeqTwoByteString: public SeqString {
|
||||
}
|
||||
|
||||
// Layout description.
|
||||
- static const int kHeaderSize = String::kSize;
|
||||
+ static const int kHeaderSize = SeqString::kSize;
|
||||
static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize);
|
||||
|
||||
// Maximal memory usage for a single sequential two-byte string.
|
||||
// Shortcuts for templates that know their string-type exactly.
|
||||
bool IsExternalAsciiString() {
|
||||
--
|
||||
1.7.4.4
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
From 530ded6ea634bccb96652cd3e0cf67725449ed63 Mon Sep 17 00:00:00 2001
|
||||
From a80d89daacb698b72f59cad5b83c1f1633a98c9f Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Mon, 23 May 2011 16:21:02 +1000
|
||||
Subject: [PATCH 03/16] Add a "fallback" mode for named property interceptors
|
||||
Date: Tue, 4 Oct 2011 15:30:20 +1000
|
||||
Subject: [PATCH 02/11] Add a "fallback" mode for named property interceptors
|
||||
|
||||
By default interceptors are called before the normal property
|
||||
resolution on objects. When an interceptor is installed as a
|
||||
@ -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
|
||||
declarations.
|
||||
---
|
||||
include/v8.h | 8 ++++++++
|
||||
include/v8.h | 7 +++++++
|
||||
src/api.cc | 29 +++++++++++++++++++++++++++++
|
||||
src/factory.cc | 4 ++++
|
||||
src/factory.cc | 3 +++
|
||||
src/handles.cc | 6 ++++--
|
||||
src/handles.h | 3 ++-
|
||||
src/objects-inl.h | 16 ++++++++++++++++
|
||||
src/objects.cc | 22 ++++++++++++++++------
|
||||
src/objects.h | 18 ++++++++++++++----
|
||||
src/objects-inl.h | 15 +++++++++++++++
|
||||
src/objects.cc | 24 +++++++++++++++++-------
|
||||
src/objects.h | 16 ++++++++++++----
|
||||
src/runtime.cc | 11 ++++++-----
|
||||
9 files changed, 99 insertions(+), 18 deletions(-)
|
||||
9 files changed, 95 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index be1ee71..bb31ea0 100644
|
||||
index 86ea70f..d2e6c32 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -2170,6 +2170,7 @@ class V8EXPORT FunctionTemplate : public Template {
|
||||
@@ -2305,6 +2305,7 @@ class V8EXPORT FunctionTemplate : public Template {
|
||||
NamedPropertyQuery query,
|
||||
NamedPropertyDeleter remover,
|
||||
NamedPropertyEnumerator enumerator,
|
||||
@ -35,25 +35,24 @@ index be1ee71..bb31ea0 100644
|
||||
Handle<Value> data);
|
||||
void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
|
||||
IndexedPropertySetter setter,
|
||||
@@ -2254,6 +2255,13 @@ class V8EXPORT ObjectTemplate : public Template {
|
||||
@@ -2388,6 +2389,12 @@ class V8EXPORT ObjectTemplate : public Template {
|
||||
NamedPropertyDeleter deleter = 0,
|
||||
NamedPropertyEnumerator enumerator = 0,
|
||||
Handle<Value> data = Handle<Value>());
|
||||
|
||||
+ void SetFallbackPropertyHandler(NamedPropertyGetter getter,
|
||||
+ NamedPropertySetter setter = 0,
|
||||
+ NamedPropertyQuery query = 0,
|
||||
+ NamedPropertyDeleter deleter = 0,
|
||||
+ NamedPropertyEnumerator enumerator = 0,
|
||||
+ Handle<Value> data = Handle<Value>());
|
||||
+
|
||||
|
||||
/**
|
||||
* Sets an indexed property handler on the object template.
|
||||
*
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index 381935b..8b0b32a 100644
|
||||
index 2d205fd..e4dd694 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
|
||||
@@ -1123,6 +1123,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
|
||||
NamedPropertyQuery query,
|
||||
NamedPropertyDeleter remover,
|
||||
NamedPropertyEnumerator enumerator,
|
||||
@ -61,7 +60,7 @@ index 381935b..8b0b32a 100644
|
||||
Handle<Value> data) {
|
||||
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
|
||||
if (IsDeadCheck(isolate,
|
||||
@@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
|
||||
@@ -1141,6 +1142,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
|
||||
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
|
||||
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
|
||||
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
|
||||
@ -69,7 +68,7 @@ index 381935b..8b0b32a 100644
|
||||
|
||||
if (data.IsEmpty()) data = v8::Undefined();
|
||||
obj->set_data(*Utils::OpenHandle(*data));
|
||||
@@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
|
||||
@@ -1285,6 +1287,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
|
||||
query,
|
||||
remover,
|
||||
enumerator,
|
||||
@ -85,7 +84,7 @@ index 381935b..8b0b32a 100644
|
||||
+ NamedPropertyEnumerator enumerator,
|
||||
+ Handle<Value> data) {
|
||||
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
|
||||
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) {
|
||||
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) {
|
||||
+ return;
|
||||
+ }
|
||||
+ ENTER_V8(isolate);
|
||||
@ -104,14 +103,13 @@ index 381935b..8b0b32a 100644
|
||||
}
|
||||
|
||||
diff --git a/src/factory.cc b/src/factory.cc
|
||||
index 7dee66f..dcdc645 100644
|
||||
index 00fc6bb..2338cda 100644
|
||||
--- a/src/factory.cc
|
||||
+++ b/src/factory.cc
|
||||
@@ -1058,6 +1058,10 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
@@ -1180,6 +1180,9 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
// Set interceptor information in the map.
|
||||
if (!obj->named_property_handler()->IsUndefined()) {
|
||||
map->set_has_named_interceptor();
|
||||
+
|
||||
+ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler());
|
||||
+ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value();
|
||||
+ map->set_named_interceptor_is_fallback(is_fallback);
|
||||
@ -119,10 +117,10 @@ index 7dee66f..dcdc645 100644
|
||||
if (!obj->indexed_property_handler()->IsUndefined()) {
|
||||
map->set_has_indexed_interceptor();
|
||||
diff --git a/src/handles.cc b/src/handles.cc
|
||||
index 326de86..dd3a86c 100644
|
||||
index ce4258d..104fc9c 100644
|
||||
--- a/src/handles.cc
|
||||
+++ b/src/handles.cc
|
||||
@@ -262,9 +262,11 @@ Handle<Object> SetProperty(Handle<JSObject> object,
|
||||
@@ -265,9 +265,11 @@ Handle<Object> SetProperty(Handle<JSReceiver> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
@ -137,10 +135,10 @@ index 326de86..dd3a86c 100644
|
||||
}
|
||||
|
||||
diff --git a/src/handles.h b/src/handles.h
|
||||
index 3839f37..4b42506 100644
|
||||
index 8dcca3e..babe763 100644
|
||||
--- a/src/handles.h
|
||||
+++ b/src/handles.h
|
||||
@@ -188,7 +188,8 @@ Handle<Object> SetProperty(Handle<JSObject> object,
|
||||
@@ -192,7 +192,8 @@ Handle<Object> SetProperty(Handle<JSReceiver> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
@ -151,13 +149,14 @@ index 3839f37..4b42506 100644
|
||||
Handle<Object> SetProperty(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
diff --git a/src/objects-inl.h b/src/objects-inl.h
|
||||
index cce3edd..6aaca2f 100644
|
||||
index 73d0ac9..35fbea5 100644
|
||||
--- a/src/objects-inl.h
|
||||
+++ b/src/objects-inl.h
|
||||
@@ -2521,6 +2521,21 @@ bool Map::is_shared() {
|
||||
@@ -2864,6 +2864,20 @@ void Map::set_is_shared(bool value) {
|
||||
bool Map::is_shared() {
|
||||
return ((1 << kIsShared) & bit_field3()) != 0;
|
||||
}
|
||||
|
||||
|
||||
+
|
||||
+void Map::set_named_interceptor_is_fallback(bool value)
|
||||
+{
|
||||
+ if (value) {
|
||||
@ -171,12 +170,10 @@ index cce3edd..6aaca2f 100644
|
||||
+{
|
||||
+ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
|
||||
|
||||
JSFunction* Map::unchecked_constructor() {
|
||||
return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
|
||||
}
|
||||
@@ -2970,6 +2985,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
|
||||
@@ -3350,6 +3364,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
|
||||
ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
|
||||
ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
|
||||
ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
|
||||
@ -185,71 +182,73 @@ index cce3edd..6aaca2f 100644
|
||||
ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
|
||||
ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
|
||||
diff --git a/src/objects.cc b/src/objects.cc
|
||||
index 79d7240..15e2cdb 100644
|
||||
index fe5bf97..8e1773f 100644
|
||||
--- a/src/objects.cc
|
||||
+++ b/src/objects.cc
|
||||
@@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
|
||||
MaybeObject* JSObject::SetProperty(String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
- StrictModeFlag strict_mode) {
|
||||
+ StrictModeFlag strict_mode,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
@@ -1838,9 +1838,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
|
||||
MaybeObject* JSReceiver::SetProperty(String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
- StrictModeFlag strict_mode) {
|
||||
+ StrictModeFlag strict_mode,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
LookupResult result;
|
||||
- LocalLookup(name, &result);
|
||||
+ LocalLookup(name, &result, skip_fallback_interceptor);
|
||||
return SetProperty(&result, name, value, attributes, strict_mode);
|
||||
}
|
||||
|
||||
@@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
|
||||
@@ -3832,7 +3833,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
|
||||
}
|
||||
|
||||
|
||||
-void JSObject::LocalLookup(String* name, LookupResult* result) {
|
||||
+void JSObject::LocalLookup(String* name, LookupResult* result,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
-void JSReceiver::LocalLookup(String* name, LookupResult* result) {
|
||||
+void JSReceiver::LocalLookup(String* name, LookupResult* result,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
ASSERT(name->IsString());
|
||||
|
||||
Heap* heap = GetHeap();
|
||||
@@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) {
|
||||
@@ -3864,23 +3866,31 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) {
|
||||
}
|
||||
|
||||
// Check for lookup interceptor except when bootstrapping.
|
||||
- if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
|
||||
+ bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive();
|
||||
- if (js_object->HasNamedInterceptor() &&
|
||||
- !heap->isolate()->bootstrapper()->IsActive()) {
|
||||
+ bool wouldIntercept = js_object->HasNamedInterceptor() &&
|
||||
+ !heap->isolate()->bootstrapper()->IsActive();
|
||||
+ if (wouldIntercept && !map()->named_interceptor_is_fallback()) {
|
||||
result->InterceptorResult(this);
|
||||
result->InterceptorResult(js_object);
|
||||
return;
|
||||
}
|
||||
|
||||
LocalLookupRealNamedProperty(name, result);
|
||||
js_object->LocalLookupRealNamedProperty(name, result);
|
||||
+
|
||||
+ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
|
||||
+ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
|
||||
+ map()->named_interceptor_is_fallback()) {
|
||||
+ result->InterceptorResult(this);
|
||||
+ result->InterceptorResult(js_object);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
-void JSObject::Lookup(String* name, LookupResult* result) {
|
||||
+void JSObject::Lookup(String* name, LookupResult* result,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
-void JSReceiver::Lookup(String* name, LookupResult* result) {
|
||||
+void JSReceiver::Lookup(String* name, LookupResult* result,
|
||||
+ bool skip_fallback_interceptor) {
|
||||
// Ecma-262 3rd 8.6.2.4
|
||||
Heap* heap = GetHeap();
|
||||
for (Object* current = this;
|
||||
current != heap->null_value();
|
||||
current = JSObject::cast(current)->GetPrototype()) {
|
||||
- JSObject::cast(current)->LocalLookup(name, result);
|
||||
+ JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor);
|
||||
- JSReceiver::cast(current)->LocalLookup(name, result);
|
||||
+ JSReceiver::cast(current)->LocalLookup(name, result, skip_fallback_interceptor);
|
||||
if (result->IsProperty()) return;
|
||||
}
|
||||
result->NotFound();
|
||||
diff --git a/src/objects.h b/src/objects.h
|
||||
index 07e1089..a209cd0 100644
|
||||
index eb4eb0e..b974756 100644
|
||||
--- a/src/objects.h
|
||||
+++ b/src/objects.h
|
||||
@@ -1405,7 +1405,8 @@ class JSObject: public HeapObject {
|
||||
@@ -1332,7 +1332,8 @@ class JSReceiver: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* SetProperty(String* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
@ -259,7 +258,7 @@ index 07e1089..a209cd0 100644
|
||||
MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
|
||||
String* key,
|
||||
Object* value,
|
||||
@@ -1637,8 +1638,8 @@ class JSObject: public HeapObject {
|
||||
@@ -1381,8 +1382,8 @@ class JSReceiver: public HeapObject {
|
||||
|
||||
// Lookup a property. If found, the result is valid and has
|
||||
// detailed information.
|
||||
@ -268,30 +267,28 @@ index 07e1089..a209cd0 100644
|
||||
+ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
|
||||
+ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
|
||||
|
||||
// The following lookup functions skip interceptors.
|
||||
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
|
||||
@@ -3714,6 +3715,12 @@ class Map: public HeapObject {
|
||||
protected:
|
||||
Smi* GenerateIdentityHash();
|
||||
@@ -4071,6 +4072,10 @@ class Map: public HeapObject {
|
||||
inline void set_is_access_check_needed(bool access_check_needed);
|
||||
inline bool is_access_check_needed();
|
||||
|
||||
+
|
||||
+ // Whether the named interceptor is a fallback interceptor or not
|
||||
+ inline void set_named_interceptor_is_fallback(bool value);
|
||||
+ inline bool named_interceptor_is_fallback();
|
||||
+
|
||||
+
|
||||
// [prototype]: implicit prototype object.
|
||||
DECL_ACCESSORS(prototype, Object)
|
||||
|
||||
@@ -3904,6 +3911,7 @@ class Map: public HeapObject {
|
||||
static const int kHasExternalArrayElements = 6;
|
||||
@@ -4307,6 +4312,7 @@ class Map: public HeapObject {
|
||||
|
||||
// Bit positions for bit field 3
|
||||
+ static const int kNamedInterceptorIsFallback = 0;
|
||||
static const int kIsShared = 0;
|
||||
+ static const int kNamedInterceptorIsFallback = 1;
|
||||
|
||||
// Layout of the default cache. It holds alternating name and code objects.
|
||||
static const int kCodeCacheEntrySize = 2;
|
||||
@@ -6276,6 +6284,7 @@ class InterceptorInfo: public Struct {
|
||||
@@ -7142,6 +7148,7 @@ class InterceptorInfo: public Struct {
|
||||
DECL_ACCESSORS(deleter, Object)
|
||||
DECL_ACCESSORS(enumerator, Object)
|
||||
DECL_ACCESSORS(data, Object)
|
||||
@ -299,7 +296,7 @@ index 07e1089..a209cd0 100644
|
||||
|
||||
static inline InterceptorInfo* cast(Object* obj);
|
||||
|
||||
@@ -6295,7 +6304,8 @@ class InterceptorInfo: public Struct {
|
||||
@@ -7161,7 +7168,8 @@ class InterceptorInfo: public Struct {
|
||||
static const int kDeleterOffset = kQueryOffset + kPointerSize;
|
||||
static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
|
||||
static const int kDataOffset = kEnumeratorOffset + kPointerSize;
|
||||
@ -310,48 +307,48 @@ index 07e1089..a209cd0 100644
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
|
||||
diff --git a/src/runtime.cc b/src/runtime.cc
|
||||
index 7335da8..660352c 100644
|
||||
index 89abf38..5a850e9 100644
|
||||
--- a/src/runtime.cc
|
||||
+++ b/src/runtime.cc
|
||||
@@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
@@ -1236,7 +1236,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
// Lookup the property in the global object, and don't set the
|
||||
// value of the variable if the property is already there.
|
||||
LookupResult lookup;
|
||||
- global->Lookup(*name, &lookup);
|
||||
+ global->Lookup(*name, &lookup, true);
|
||||
if (lookup.IsProperty()) {
|
||||
// Determine if the property is local by comparing the holder
|
||||
// against the global object. The information will be used to
|
||||
@@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
// We found an existing property. Unless it was an interceptor
|
||||
// that claims the property is absent, skip this declaration.
|
||||
@@ -1263,7 +1263,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
}
|
||||
|
||||
LookupResult lookup;
|
||||
- global->LocalLookup(*name, &lookup);
|
||||
+ global->LocalLookup(*name, &lookup, true);
|
||||
|
||||
PropertyAttributes attributes = is_const_property
|
||||
? static_cast<PropertyAttributes>(base | READ_ONLY)
|
||||
@@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
// Compute the property attributes. According to ECMA-262, section
|
||||
// 13, page 71, the property must be read-only and
|
||||
@@ -1306,7 +1306,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
|
||||
name,
|
||||
value,
|
||||
attributes,
|
||||
static_cast<PropertyAttributes>(attr),
|
||||
- strict_mode));
|
||||
+ strict_mode,
|
||||
+ true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
|
||||
JSObject* real_holder = global;
|
||||
LookupResult lookup;
|
||||
while (true) {
|
||||
- real_holder->LocalLookup(*name, &lookup);
|
||||
+ real_holder->LocalLookup(*name, &lookup, true);
|
||||
if (lookup.IsProperty()) {
|
||||
// Determine if this is a redeclaration of something read-only.
|
||||
if (lookup.IsReadOnly()) {
|
||||
@@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
|
||||
|
||||
@@ -1442,7 +1443,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
|
||||
while (object->IsJSObject() &&
|
||||
JSObject::cast(object)->map()->is_hidden_prototype()) {
|
||||
JSObject* raw_holder = JSObject::cast(object);
|
||||
- raw_holder->LocalLookup(*name, &lookup);
|
||||
+ raw_holder->LocalLookup(*name, &lookup, true);
|
||||
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
|
||||
HandleScope handle_scope(isolate);
|
||||
Handle<JSObject> holder(raw_holder);
|
||||
@@ -1465,7 +1466,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
|
||||
// Reload global in case the loop above performed a GC.
|
||||
global = isolate->context()->global();
|
||||
if (assign) {
|
||||
- return global->SetProperty(*name, args[2], attributes, strict_mode);
|
595
src/v8/0003-Generalize-external-object-resources.patch
Normal file
595
src/v8/0003-Generalize-external-object-resources.patch
Normal file
@ -0,0 +1,595 @@
|
||||
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
|
||||
|
@ -1,894 +0,0 @@
|
||||
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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
From 1209b88e96f253cdc19aa4c95e011c84597844f0 Mon Sep 17 00:00:00 2001
|
||||
From 2608243d70a8fcb0335f3520d5de1ac3cd854e87 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Wed, 25 May 2011 10:36:13 +1000
|
||||
Subject: [PATCH 06/16] Allow access to the calling script data
|
||||
Date: Fri, 14 Oct 2011 17:03:06 +1000
|
||||
Subject: [PATCH 05/11] Allow access to the calling script data
|
||||
|
||||
---
|
||||
include/v8.h | 1 +
|
||||
@ -9,10 +9,10 @@ Subject: [PATCH 06/16] Allow access to the calling script data
|
||||
2 files changed, 13 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index d78ab1f..2bc0ed1 100644
|
||||
index 193e2fe..c094d08 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -3337,6 +3337,7 @@ class V8EXPORT Context {
|
||||
@@ -3517,6 +3517,7 @@ class V8EXPORT Context {
|
||||
*/
|
||||
static Local<Context> GetCalling();
|
||||
static Local<Object> GetCallingQmlGlobal();
|
||||
@ -21,10 +21,10 @@ index d78ab1f..2bc0ed1 100644
|
||||
/**
|
||||
* Sets the security token for the context. To access an object in
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index 39767f4..ff74efb 100644
|
||||
index fd718c8..526aa02 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -3976,6 +3976,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
|
||||
@@ -4361,6 +4361,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
From a7c491e6e533110a17fe9f7d47cf92a1b2263180 Mon Sep 17 00:00:00 2001
|
||||
From 1c747846df3be9021aff2b0fc402cdd3a239e86b Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Mon, 27 Jun 2011 14:57:28 +1000
|
||||
Subject: [PATCH 08/16] Add custom object compare callback
|
||||
Date: Wed, 25 May 2011 10:36:13 +1000
|
||||
Subject: [PATCH 06/11] Add custom object compare callback
|
||||
|
||||
A global custom object comparison callback can be set with:
|
||||
V8::SetUserObjectComparisonCallbackFunction()
|
||||
@ -14,24 +14,25 @@ compare as equal, even though they are actually different JS object
|
||||
instances.
|
||||
---
|
||||
include/v8.h | 13 +++++++++++++
|
||||
src/api.cc | 19 +++++++++++++++++++
|
||||
src/arm/code-stubs-arm.cc | 42 ++++++++++++++++++++++++++++++++++++++++--
|
||||
src/api.cc | 22 ++++++++++++++++++++++
|
||||
src/arm/code-stubs-arm.cc | 43 +++++++++++++++++++++++++++++++++++++++++--
|
||||
src/factory.cc | 8 ++++++++
|
||||
src/ia32/code-stubs-ia32.cc | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
src/ia32/code-stubs-ia32.cc | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
src/isolate.cc | 7 +++++++
|
||||
src/isolate.h | 8 ++++++++
|
||||
src/objects-inl.h | 15 +++++++++++++++
|
||||
src/objects.h | 10 +++++++++-
|
||||
src/objects-inl.h | 21 ++++++++++++++++++---
|
||||
src/objects.cc | 8 ++++----
|
||||
src/objects.h | 12 ++++++++++--
|
||||
src/runtime.cc | 23 +++++++++++++++++++++++
|
||||
src/runtime.h | 1 +
|
||||
src/top.cc | 5 +++++
|
||||
src/x64/code-stubs-x64.cc | 37 +++++++++++++++++++++++++++++++++++++
|
||||
12 files changed, 218 insertions(+), 3 deletions(-)
|
||||
13 files changed, 231 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index 99f4b9a..7544deb 100644
|
||||
index c094d08..6baf2b2 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -2366,6 +2366,12 @@ class V8EXPORT ObjectTemplate : public Template {
|
||||
@@ -2501,6 +2501,12 @@ class V8EXPORT ObjectTemplate : public Template {
|
||||
bool HasExternalResource();
|
||||
void SetHasExternalResource(bool value);
|
||||
|
||||
@ -44,18 +45,18 @@ index 99f4b9a..7544deb 100644
|
||||
private:
|
||||
ObjectTemplate();
|
||||
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
|
||||
@@ -2566,6 +2572,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
|
||||
@@ -2720,6 +2726,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
|
||||
AccessType type,
|
||||
Local<Value> data);
|
||||
|
||||
+// --- U s e r O b j e c t C o m p a r i s o n C a l l b a c k ---
|
||||
+// --- User Object Comparisoa nCallback ---
|
||||
+typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
|
||||
+ Local<Object> rhs);
|
||||
+
|
||||
// --- G a r b a g e C o l l e c t i o n C a l l b a c k s
|
||||
// --- AllowCodeGenerationFromStrings callbacks ---
|
||||
|
||||
/**
|
||||
@@ -2816,6 +2826,9 @@ class V8EXPORT V8 {
|
||||
@@ -3046,6 +3056,9 @@ class V8EXPORT V8 {
|
||||
/** Callback function for reporting failed access checks.*/
|
||||
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
|
||||
|
||||
@ -66,13 +67,13 @@ index 99f4b9a..7544deb 100644
|
||||
* Enables the host application to receive a notification before a
|
||||
* garbage collection. Allocations are not allowed in the
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index ff74efb..2436031 100644
|
||||
index 526aa02..6f6297d 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -1321,6 +1321,16 @@ void ObjectTemplate::SetHasExternalResource(bool value)
|
||||
}
|
||||
@@ -1464,6 +1464,17 @@ void ObjectTemplate::SetHasExternalResource(bool value)
|
||||
}
|
||||
|
||||
|
||||
+void ObjectTemplate::MarkAsUseUserObjectComparison()
|
||||
+{
|
||||
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
|
||||
@ -83,13 +84,15 @@ index ff74efb..2436031 100644
|
||||
+ EnsureConstructor(this);
|
||||
+ Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1));
|
||||
+}
|
||||
|
||||
+
|
||||
// --- S c r i p t D a t a ---
|
||||
|
||||
@@ -4632,6 +4642,15 @@ void V8::SetFailedAccessCheckCallbackFunction(
|
||||
|
||||
@@ -5106,6 +5117,17 @@ void V8::SetFailedAccessCheckCallbackFunction(
|
||||
isolate->SetFailedAccessCheckCallback(callback);
|
||||
}
|
||||
|
||||
+
|
||||
+void V8::SetUserObjectComparisonCallbackFunction(
|
||||
+ UserObjectComparisonCallback callback) {
|
||||
+ i::Isolate* isolate = i::Isolate::Current();
|
||||
@ -98,15 +101,16 @@ index ff74efb..2436031 100644
|
||||
+ }
|
||||
+ isolate->SetUserObjectComparisonCallback(callback);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void V8::AddObjectGroup(Persistent<Value>* objects,
|
||||
size_t length,
|
||||
RetainedObjectInfo* info) {
|
||||
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
|
||||
index a2626bf..749c9be 100644
|
||||
index 00ac676..a67b3a0 100644
|
||||
--- a/src/arm/code-stubs-arm.cc
|
||||
+++ b/src/arm/code-stubs-arm.cc
|
||||
@@ -1563,6 +1563,36 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
@@ -1494,6 +1494,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
// it is certain that at least one operand isn't a smi.
|
||||
|
||||
@ -122,12 +126,12 @@ index a2626bf..749c9be 100644
|
||||
+ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
|
||||
+ __ b(ne, ¬_user_equal);
|
||||
+
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
|
||||
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ b(eq, &user_equal);
|
||||
+
|
||||
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField3Offset));
|
||||
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset));
|
||||
+ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ b(ne, ¬_user_equal);
|
||||
@ -139,25 +143,26 @@ index a2626bf..749c9be 100644
|
||||
+
|
||||
+ __ bind(¬_user_equal);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
// Handle the case where the objects are identical. Either returns the answer
|
||||
// or goes to slow. Only falls through if the objects were not identical.
|
||||
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
|
||||
@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
__ tst(r2, Operand(kSmiTagMask));
|
||||
__ b(eq, &miss);
|
||||
@@ -6544,10 +6575,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
__ and_(r2, r1, Operand(r0));
|
||||
__ JumpIfSmi(r2, &miss);
|
||||
|
||||
- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
|
||||
+ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
|
||||
__ b(ne, &miss);
|
||||
- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
|
||||
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ b(eq, &miss);
|
||||
+ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
|
||||
__ b(ne, &miss);
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField3Offset));
|
||||
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
|
||||
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
|
||||
+ __ b(eq, &miss);
|
||||
@ -165,10 +170,10 @@ index a2626bf..749c9be 100644
|
||||
ASSERT(GetCondition() == eq);
|
||||
__ sub(r0, r0, Operand(r1));
|
||||
diff --git a/src/factory.cc b/src/factory.cc
|
||||
index d530a75..6f8c7de 100644
|
||||
index e3cccae..96d3458 100644
|
||||
--- a/src/factory.cc
|
||||
+++ b/src/factory.cc
|
||||
@@ -998,6 +998,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
@@ -1120,6 +1120,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
|
||||
int internal_field_count = 0;
|
||||
bool has_external_resource = false;
|
||||
@ -176,7 +181,7 @@ index d530a75..6f8c7de 100644
|
||||
|
||||
if (!obj->instance_template()->IsUndefined()) {
|
||||
Handle<ObjectTemplateInfo> instance_template =
|
||||
@@ -1007,6 +1008,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
@@ -1129,6 +1130,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
Smi::cast(instance_template->internal_field_count())->value();
|
||||
has_external_resource =
|
||||
!instance_template->has_external_resource()->IsUndefined();
|
||||
@ -185,7 +190,7 @@ index d530a75..6f8c7de 100644
|
||||
}
|
||||
|
||||
int instance_size = kPointerSize * internal_field_count;
|
||||
@@ -1051,6 +1054,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
@@ -1173,6 +1176,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
|
||||
map->set_has_external_resource(true);
|
||||
}
|
||||
|
||||
@ -198,15 +203,15 @@ index d530a75..6f8c7de 100644
|
||||
if (obj->undetectable()) {
|
||||
map->set_is_undetectable();
|
||||
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
|
||||
index afa599e..0964ab9 100644
|
||||
index 6cc80d3..cabf78f 100644
|
||||
--- a/src/ia32/code-stubs-ia32.cc
|
||||
+++ b/src/ia32/code-stubs-ia32.cc
|
||||
@@ -3447,6 +3447,40 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
__ Assert(not_zero, "Unexpected smi operands.");
|
||||
}
|
||||
@@ -3931,6 +3931,39 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
// it is certain that at least one operand isn't a smi.
|
||||
|
||||
+ {
|
||||
+ NearLabel not_user_equal, user_equal;
|
||||
+ Label not_user_equal, user_equal;
|
||||
+ __ test(eax, Immediate(kSmiTagMask));
|
||||
+ __ j(zero, ¬_user_equal);
|
||||
+ __ test(edx, Immediate(kSmiTagMask));
|
||||
@ -218,10 +223,10 @@ index afa599e..0964ab9 100644
|
||||
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
|
||||
+ __ j(not_equal, ¬_user_equal);
|
||||
+
|
||||
+ __ test_b(FieldOperand(ebx, Map::kBitField3Offset),
|
||||
+ __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
|
||||
+ 1 << Map::kUseUserObjectComparison);
|
||||
+ __ j(not_zero, &user_equal);
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
|
||||
+ 1 << Map::kUseUserObjectComparison);
|
||||
+ __ j(not_zero, &user_equal);
|
||||
+
|
||||
@ -238,40 +243,64 @@ index afa599e..0964ab9 100644
|
||||
+ __ bind(¬_user_equal);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
// it is certain that at least one operand isn't a smi.
|
||||
|
||||
@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
// Identical objects can be compared fast, but there are some tricky cases
|
||||
// for NaN and undefined.
|
||||
{
|
||||
@@ -6409,8 +6442,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
|
||||
__ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
|
||||
__ j(not_equal, &miss, Label::kNear);
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
|
||||
+ 1 << Map::kUseUserObjectComparison);
|
||||
+ __ j(not_zero, &miss);
|
||||
+ __ j(not_zero, &miss, Label::kNear);
|
||||
__ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField3Offset),
|
||||
__ j(not_equal, &miss, Label::kNear);
|
||||
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
|
||||
+ 1 << Map::kUseUserObjectComparison);
|
||||
+ __ j(not_zero, &miss);
|
||||
+ __ j(not_zero, &miss, Label::kNear);
|
||||
|
||||
ASSERT(GetCondition() == equal);
|
||||
__ sub(eax, Operand(edx));
|
||||
__ sub(eax, 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
|
||||
index 35ffcb4..8130397 100644
|
||||
index 01ab04e..06ef22d 100644
|
||||
--- a/src/isolate.h
|
||||
+++ b/src/isolate.h
|
||||
@@ -267,6 +267,9 @@ class ThreadLocalTop BASE_EMBEDDED {
|
||||
@@ -255,6 +255,9 @@ class ThreadLocalTop BASE_EMBEDDED {
|
||||
// Call back function to report unsafe JS accesses.
|
||||
v8::FailedAccessCheckCallback failed_access_check_callback_;
|
||||
|
||||
+ // Call back function for user object comparisons
|
||||
+ v8::UserObjectComparisonCallback user_object_comparison_callback_;
|
||||
+
|
||||
private:
|
||||
void InitializeInternal();
|
||||
// Whether out of memory exceptions should be ignored.
|
||||
bool ignore_out_of_memory_;
|
||||
|
||||
@@ -699,6 +702,11 @@ class Isolate {
|
||||
@@ -701,6 +704,11 @@ class Isolate {
|
||||
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
|
||||
void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
|
||||
|
||||
@ -284,63 +313,116 @@ index 35ffcb4..8130397 100644
|
||||
// of Throw() as its return value.
|
||||
Failure* Throw(Object* exception, MessageLocation* location = NULL);
|
||||
diff --git a/src/objects-inl.h b/src/objects-inl.h
|
||||
index 1c7f83e..1765441 100644
|
||||
index 375df0f..4657482 100644
|
||||
--- a/src/objects-inl.h
|
||||
+++ b/src/objects-inl.h
|
||||
@@ -2552,6 +2552,19 @@ bool Map::has_external_resource()
|
||||
@@ -2859,14 +2859,14 @@ bool Map::is_extensible() {
|
||||
|
||||
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) {
|
||||
+ if (value) {
|
||||
+ set_bit_field3(bit_field3() | (1 << kUseUserObjectComparison));
|
||||
+ set_bit_field2(bit_field2() | (1 << kUseUserObjectComparison));
|
||||
+ } else {
|
||||
+ set_bit_field3(bit_field3() & ~(1 << kUseUserObjectComparison));
|
||||
+ set_bit_field2(bit_field2() & ~(1 << kUseUserObjectComparison));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+bool Map::use_user_object_comparison() {
|
||||
+ return ((1 << kUseUserObjectComparison) & bit_field3()) != 0;
|
||||
+ return ((1 << kUseUserObjectComparison) & bit_field2()) != 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
void Map::set_named_interceptor_is_fallback(bool value)
|
||||
{
|
||||
if (value) {
|
||||
@@ -3050,6 +3063,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
|
||||
@@ -3429,6 +3442,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
|
||||
kInternalFieldCountOffset)
|
||||
ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
|
||||
ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
|
||||
kHasExternalResourceOffset)
|
||||
+ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
|
||||
+ kUseUserObjectComparisonOffset)
|
||||
|
||||
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
|
||||
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
|
||||
diff --git a/src/objects.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
|
||||
index edbc47a..e75e9f1 100644
|
||||
index 71895be..881c24e 100644
|
||||
--- a/src/objects.h
|
||||
+++ b/src/objects.h
|
||||
@@ -3724,6 +3724,11 @@ class Map: public HeapObject {
|
||||
@@ -4084,6 +4084,11 @@ class Map: public HeapObject {
|
||||
inline void set_has_external_resource(bool value);
|
||||
inline bool has_external_resource();
|
||||
|
||||
+
|
||||
+ // Tells whether the user object comparison callback should be used for
|
||||
+ // comparisons involving this object
|
||||
+ inline void set_use_user_object_comparison(bool value);
|
||||
+ inline bool use_user_object_comparison();
|
||||
|
||||
// Whether the named interceptor is a fallback interceptor or not
|
||||
inline void set_named_interceptor_is_fallback(bool value);
|
||||
@@ -3922,6 +3927,7 @@ class Map: public HeapObject {
|
||||
// Bit positions for bit field 3
|
||||
static const int kNamedInterceptorIsFallback = 0;
|
||||
static const int kHasExternalResource = 1;
|
||||
+ static const int kUseUserObjectComparison = 2;
|
||||
+
|
||||
// [prototype]: implicit prototype object.
|
||||
DECL_ACCESSORS(prototype, Object)
|
||||
|
||||
@@ -4303,7 +4308,7 @@ class Map: public HeapObject {
|
||||
static const int kIsExtensible = 0;
|
||||
static const int kFunctionWithPrototype = 1;
|
||||
static const int kStringWrapperSafeForDefaultValueOf = 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.
|
||||
static const int kCodeCacheEntrySize = 2;
|
||||
@@ -6442,6 +6448,7 @@ class ObjectTemplateInfo: public TemplateInfo {
|
||||
@@ -7306,6 +7312,7 @@ class ObjectTemplateInfo: public TemplateInfo {
|
||||
DECL_ACCESSORS(constructor, Object)
|
||||
DECL_ACCESSORS(internal_field_count, Object)
|
||||
DECL_ACCESSORS(has_external_resource, Object)
|
||||
@ -348,7 +430,7 @@ index edbc47a..e75e9f1 100644
|
||||
|
||||
static inline ObjectTemplateInfo* cast(Object* obj);
|
||||
|
||||
@@ -6459,7 +6466,8 @@ class ObjectTemplateInfo: public TemplateInfo {
|
||||
@@ -7323,7 +7330,8 @@ class ObjectTemplateInfo: public TemplateInfo {
|
||||
static const int kInternalFieldCountOffset =
|
||||
kConstructorOffset + kPointerSize;
|
||||
static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
|
||||
@ -359,10 +441,10 @@ index edbc47a..e75e9f1 100644
|
||||
|
||||
|
||||
diff --git a/src/runtime.cc b/src/runtime.cc
|
||||
index c13f92d..b50de80 100644
|
||||
index 0388a77..24b3de0 100644
|
||||
--- a/src/runtime.cc
|
||||
+++ b/src/runtime.cc
|
||||
@@ -6279,6 +6279,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
|
||||
@@ -7008,6 +7008,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
|
||||
}
|
||||
|
||||
|
||||
@ -393,10 +475,10 @@ index c13f92d..b50de80 100644
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 3);
|
||||
diff --git a/src/runtime.h b/src/runtime.h
|
||||
index 5e97173..0d754f9 100644
|
||||
index 284f723..5d6bf5e 100644
|
||||
--- a/src/runtime.h
|
||||
+++ b/src/runtime.h
|
||||
@@ -146,6 +146,7 @@ namespace internal {
|
||||
@@ -157,6 +157,7 @@ namespace internal {
|
||||
/* Comparisons */ \
|
||||
F(NumberEquals, 2, 1) \
|
||||
F(StringEquals, 2, 1) \
|
||||
@ -404,39 +486,16 @@ index 5e97173..0d754f9 100644
|
||||
\
|
||||
F(NumberCompare, 3, 1) \
|
||||
F(SmiLexicographicCompare, 2, 1) \
|
||||
diff --git a/src/top.cc b/src/top.cc
|
||||
index e078ee9..c345383 100644
|
||||
--- a/src/top.cc
|
||||
+++ b/src/top.cc
|
||||
@@ -68,6 +68,7 @@ void ThreadLocalTop::InitializeInternal() {
|
||||
thread_id_ = ThreadId::Invalid();
|
||||
external_caught_exception_ = false;
|
||||
failed_access_check_callback_ = NULL;
|
||||
+ user_object_comparison_callback_ = NULL;
|
||||
save_context_ = NULL;
|
||||
catcher_ = NULL;
|
||||
}
|
||||
@@ -387,6 +388,10 @@ void Isolate::SetFailedAccessCheckCallback(
|
||||
thread_local_top()->failed_access_check_callback_ = callback;
|
||||
}
|
||||
|
||||
+void Isolate::SetUserObjectComparisonCallback(
|
||||
+ v8::UserObjectComparisonCallback callback) {
|
||||
+ thread_local_top()->user_object_comparison_callback_ = callback;
|
||||
+}
|
||||
|
||||
void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
|
||||
if (!thread_local_top()->failed_access_check_callback_) return;
|
||||
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
||||
index d923494..10b9b56 100644
|
||||
index 6ab12fc..3be2c4b 100644
|
||||
--- a/src/x64/code-stubs-x64.cc
|
||||
+++ b/src/x64/code-stubs-x64.cc
|
||||
@@ -2443,6 +2443,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
__ bind(&ok);
|
||||
}
|
||||
@@ -3005,6 +3005,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
// it is certain that at least one operand isn't a smi.
|
||||
|
||||
+ {
|
||||
+ NearLabel not_user_equal, user_equal;
|
||||
+ Label not_user_equal, user_equal;
|
||||
+ __ JumpIfSmi(rax, ¬_user_equal);
|
||||
+ __ JumpIfSmi(rdx, ¬_user_equal);
|
||||
+
|
||||
@ -446,10 +505,10 @@ index d923494..10b9b56 100644
|
||||
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
|
||||
+ __ j(not_equal, ¬_user_equal);
|
||||
+
|
||||
+ __ testb(FieldOperand(rbx, Map::kBitField3Offset),
|
||||
+ __ testb(FieldOperand(rbx, Map::kBitField2Offset),
|
||||
+ Immediate(1 << Map::kUseUserObjectComparison));
|
||||
+ __ j(not_zero, &user_equal);
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
|
||||
+ Immediate(1 << Map::kUseUserObjectComparison));
|
||||
+ __ j(not_zero, &user_equal);
|
||||
+
|
||||
@ -466,21 +525,21 @@ index d923494..10b9b56 100644
|
||||
+ __ bind(¬_user_equal);
|
||||
+ }
|
||||
+
|
||||
// The compare stub returns a positive, negative, or zero 64-bit integer
|
||||
// value in rax, corresponding to result of comparing the two inputs.
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
// Two identical objects are equal unless they are both NaN or undefined.
|
||||
{
|
||||
Label not_identical;
|
||||
@@ -5337,8 +5368,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
|
||||
|
||||
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
|
||||
__ j(not_equal, &miss, Label::kNear);
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
|
||||
+ Immediate(1 << Map::kUseUserObjectComparison));
|
||||
+ __ j(not_zero, &miss);
|
||||
+ __ j(not_zero, &miss, Label::kNear);
|
||||
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
|
||||
__ j(not_equal, &miss, not_taken);
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField3Offset),
|
||||
__ j(not_equal, &miss, Label::kNear);
|
||||
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
|
||||
+ Immediate(1 << Map::kUseUserObjectComparison));
|
||||
+ __ j(not_zero, &miss);
|
||||
+ __ j(not_zero, &miss, Label::kNear);
|
||||
|
||||
ASSERT(GetCondition() == equal);
|
||||
__ subq(rax, rdx);
|
@ -1,7 +1,7 @@
|
||||
From 523f03f03b1ac16d272a13389f8a5654d9ff12e6 Mon Sep 17 00:00:00 2001
|
||||
From a1572a979803dda787be4a7095d5c37e926443a7 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Fri, 9 Sep 2011 14:16:12 +1000
|
||||
Subject: [PATCH 15/16] Allow a script to be flagged as "native"
|
||||
Subject: [PATCH 07/11] Allow a script to be flagged as "native"
|
||||
|
||||
Native scripts do not appear in backtraces, or in the source and
|
||||
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(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index 5e1ce50..a2d61d1 100644
|
||||
index 6baf2b2..229ddbd 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -578,8 +578,9 @@ class ScriptOrigin {
|
||||
@@ -588,8 +588,9 @@ class ScriptOrigin {
|
||||
class V8EXPORT Script {
|
||||
public:
|
||||
enum CompileFlags {
|
||||
@ -29,10 +29,10 @@ index 5e1ce50..a2d61d1 100644
|
||||
|
||||
/**
|
||||
diff --git a/src/compiler.cc b/src/compiler.cc
|
||||
index d2191b9..873018c 100755
|
||||
index 596df4a..b760b71 100644
|
||||
--- a/src/compiler.cc
|
||||
+++ b/src/compiler.cc
|
||||
@@ -507,7 +507,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
@@ -501,7 +501,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
|
||||
// Create a script object describing the script to be compiled.
|
||||
Handle<Script> script = FACTORY->NewScript(source);
|
@ -1,7 +1,7 @@
|
||||
From 5f3e5dd6901b54707ea4f868d8fa7317c4ab3852 Mon Sep 17 00:00:00 2001
|
||||
From 3c304e3712ebf9f0df0b544032f0f83945d08028 Mon Sep 17 00:00:00 2001
|
||||
From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
|
||||
Date: Tue, 7 Dec 2010 11:56:42 +0100
|
||||
Subject: [PATCH 11/16] QtScript/V8: Add new v8 api to check if a value is an
|
||||
Subject: [PATCH 08/11] QtScript/V8: Add new v8 api to check if a value is an
|
||||
error.
|
||||
|
||||
New function v8::Value::IsError was created.
|
||||
@ -15,10 +15,10 @@ research.
|
||||
3 files changed, 12 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index 18527e1..43e00f5 100644
|
||||
index 229ddbd..d995e54 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -937,6 +937,11 @@ class Value : public Data {
|
||||
@@ -967,6 +967,11 @@ class Value : public Data {
|
||||
*/
|
||||
V8EXPORT bool IsRegExp() const;
|
||||
|
||||
@ -31,10 +31,10 @@ index 18527e1..43e00f5 100644
|
||||
V8EXPORT Local<Number> ToNumber() const;
|
||||
V8EXPORT Local<String> ToString() const;
|
||||
diff --git a/src/api.cc b/src/api.cc
|
||||
index 1a585d6..bd435eb 100644
|
||||
index 6f6297d..c21af67 100644
|
||||
--- a/src/api.cc
|
||||
+++ b/src/api.cc
|
||||
@@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const {
|
||||
@@ -2316,6 +2316,12 @@ bool Value::IsRegExp() const {
|
||||
return obj->IsJSRegExp();
|
||||
}
|
||||
|
||||
@ -48,10 +48,10 @@ index 1a585d6..bd435eb 100644
|
||||
Local<String> Value::ToString() const {
|
||||
i::Handle<i::Object> obj = Utils::OpenHandle(this);
|
||||
diff --git a/src/heap.h b/src/heap.h
|
||||
index 8cbf378..db90bb9 100644
|
||||
index bab4c63..ad83b70 100644
|
||||
--- a/src/heap.h
|
||||
+++ b/src/heap.h
|
||||
@@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_();
|
||||
@@ -188,6 +188,7 @@ inline Heap* _inline_get_heap_();
|
||||
V(string_symbol, "string") \
|
||||
V(String_symbol, "String") \
|
||||
V(Date_symbol, "Date") \
|
@ -1,287 +0,0 @@
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
From ed5cc903d70f73780e5985e7d2de33f6b8d86402 Mon Sep 17 00:00:00 2001
|
||||
From 234a7bf490c4870f2d015221bb5158de4933519c Mon Sep 17 00:00:00 2001
|
||||
From: Kent Hansen <kent.hansen@nokia.com>
|
||||
Date: Fri, 2 Sep 2011 12:03:09 +0200
|
||||
Subject: [PATCH 14/16] Fix deprecated Python code
|
||||
Subject: [PATCH 09/11] Fix deprecated Python code
|
||||
|
||||
Needed to make the scripts run on Python 3, which is the
|
||||
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(-)
|
||||
|
||||
diff --git a/tools/js2c.py b/tools/js2c.py
|
||||
index 2da132f..d13d53d 100755
|
||||
index a2ea8ea..fe6a72e 100644
|
||||
--- a/tools/js2c.py
|
||||
+++ b/tools/js2c.py
|
||||
@@ -187,14 +187,14 @@ def ReadMacros(lines):
|
||||
@@ -194,14 +194,14 @@ def ReadMacros(lines):
|
||||
macro_match = MACRO_PATTERN.match(line)
|
||||
if macro_match:
|
||||
name = macro_match.group(1)
|
@ -1,398 +0,0 @@
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
From c36be227e9d7952a1952caa529c78ecdc376bd55 Mon Sep 17 00:00:00 2001
|
||||
From 8796bc9571db9f7049c96a9829281fedc54f8f38 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Thu, 25 Aug 2011 11:09:58 +1000
|
||||
Subject: [PATCH 13/16] Remove execute flag from v8-debug.h
|
||||
Subject: [PATCH 10/11] Remove execute flag from v8-debug.h
|
||||
|
||||
---
|
||||
0 files changed, 0 insertions(+), 0 deletions(-)
|
@ -1,18 +1,18 @@
|
||||
From 2a5cf85d7fd7912e516138db03e4cda47cc2a1ab Mon Sep 17 00:00:00 2001
|
||||
From 9c0d93bfae724e29ef63456942d9ddca10ca5825 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Kennedy <aaron.kennedy@nokia.com>
|
||||
Date: Fri, 27 May 2011 13:04:15 +1000
|
||||
Subject: [PATCH 07/16] Fix warnings
|
||||
Subject: [PATCH 11/11] Fix warnings
|
||||
|
||||
---
|
||||
include/v8.h | 16 ++++++++--------
|
||||
1 files changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index 2bc0ed1..99f4b9a 100644
|
||||
index d995e54..a7b5c8a 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -2416,7 +2416,7 @@ class V8EXPORT Extension { // NOLINT
|
||||
const char** deps = 0);
|
||||
@@ -2579,7 +2579,7 @@ class V8EXPORT Extension { // NOLINT
|
||||
int source_length = -1);
|
||||
virtual ~Extension() { }
|
||||
virtual v8::Handle<v8::FunctionTemplate>
|
||||
- GetNativeFunction(v8::Handle<v8::String> name) {
|
||||
@ -20,7 +20,7 @@ index 2bc0ed1..99f4b9a 100644
|
||||
return v8::Handle<v8::FunctionTemplate>();
|
||||
}
|
||||
|
||||
@@ -3722,13 +3722,13 @@ class Internals {
|
||||
@@ -3946,13 +3946,13 @@ class Internals {
|
||||
return *reinterpret_cast<T*>(addr);
|
||||
}
|
||||
|
@ -1,116 +0,0 @@
|
||||
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
|
||||
|
@ -1,61 +0,0 @@
|
||||
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
|
||||
|
@ -1 +1 @@
|
||||
These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2
|
||||
These patches apply cleanly against v8 at bd43701b639856950d7cb461d777193a51c4859c
|
||||
|
@ -72,10 +72,10 @@ SOURCES += \
|
||||
$$V8SRC/disassembler.cc \
|
||||
$$V8SRC/diy-fp.cc \
|
||||
$$V8SRC/dtoa.cc \
|
||||
$$V8SRC/elements.cc \
|
||||
$$V8SRC/execution.cc \
|
||||
$$V8SRC/factory.cc \
|
||||
$$V8SRC/flags.cc \
|
||||
$$V8SRC/frame-element.cc \
|
||||
$$V8SRC/frames.cc \
|
||||
$$V8SRC/full-codegen.cc \
|
||||
$$V8SRC/func-name-inferrer.cc \
|
||||
@ -90,6 +90,7 @@ SOURCES += \
|
||||
$$V8SRC/hydrogen.cc \
|
||||
$$V8SRC/hydrogen-instructions.cc \
|
||||
$$V8SRC/ic.cc \
|
||||
$$V8SRC/incremental-marking.cc \
|
||||
$$V8SRC/inspector.cc \
|
||||
$$V8SRC/interpreter-irregexp.cc \
|
||||
$$V8SRC/isolate.cc \
|
||||
@ -117,8 +118,8 @@ SOURCES += \
|
||||
$$V8SRC/runtime.cc \
|
||||
$$V8SRC/runtime-profiler.cc \
|
||||
$$V8SRC/safepoint-table.cc \
|
||||
$$V8SRC/scanner-base.cc \
|
||||
$$V8SRC/scanner.cc \
|
||||
$$V8SRC/scanner-character-streams.cc \
|
||||
$$V8SRC/scopeinfo.cc \
|
||||
$$V8SRC/scopes.cc \
|
||||
$$V8SRC/serialize.cc \
|
||||
@ -129,15 +130,17 @@ SOURCES += \
|
||||
$$V8SRC/strtod.cc \
|
||||
$$V8SRC/stub-cache.cc \
|
||||
$$V8SRC/token.cc \
|
||||
$$V8SRC/top.cc \
|
||||
$$V8SRC/type-info.cc \
|
||||
$$V8SRC/unicode.cc \
|
||||
$$V8SRC/utils.cc \
|
||||
$$V8SRC/v8-counters.cc \
|
||||
$$V8SRC/v8.cc \
|
||||
$$V8SRC/v8conversions.cc \
|
||||
$$V8SRC/v8threads.cc \
|
||||
$$V8SRC/v8utils.cc \
|
||||
$$V8SRC/variables.cc \
|
||||
$$V8SRC/version.cc \
|
||||
$$V8SRC/store-buffer.cc \
|
||||
$$V8SRC/zone.cc \
|
||||
$$V8SRC/extensions/gc-extension.cc \
|
||||
$$V8SRC/extensions/externalize-string-extension.cc
|
||||
@ -258,7 +261,11 @@ V8_LIBRARY_FILES = \
|
||||
$$V8SRC/mirror-debugger.js \
|
||||
$$V8SRC/debug-debugger.js
|
||||
|
||||
v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp $$V8_GENERATED_SOURCES_DIR/libraries-empty.cpp CORE
|
||||
V8_EXPERIMENTAL_LIBRARY_FILES = \
|
||||
$$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.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp
|
||||
v8_js2c.input = V8_LIBRARY_FILES
|
||||
@ -268,4 +275,15 @@ v8_js2c.depends = $$V8DIR/tools/js2c.py $$V8SRC/macros.py
|
||||
v8_js2c.CONFIG += combine
|
||||
v8_js2c.name = generating[v8] ${QMAKE_FILE_IN}
|
||||
silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands
|
||||
QMAKE_EXTRA_COMPILERS += v8_js2c
|
||||
|
||||
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
|
||||
|
@ -57,6 +57,7 @@ private slots:
|
||||
void eval();
|
||||
void evalwithinwith();
|
||||
void userobjectcompare();
|
||||
void externalteardown();
|
||||
};
|
||||
|
||||
void tst_v8::eval()
|
||||
@ -74,6 +75,11 @@ void tst_v8::userobjectcompare()
|
||||
QVERIFY(v8test_userobjectcompare());
|
||||
}
|
||||
|
||||
void tst_v8::externalteardown()
|
||||
{
|
||||
QVERIFY(v8test_externalteardown());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
V8::SetFlagsFromCommandLine(&argc, argv, true);
|
||||
|
@ -45,6 +45,8 @@
|
||||
#define RUN_TEST(testname) { \
|
||||
if (!v8test_ ## testname()) \
|
||||
printf ("Test %s FAILED\n", # testname); \
|
||||
else \
|
||||
printf ("Test %s PASS\n", # testname); \
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -54,6 +56,7 @@ int main(int argc, char *argv[])
|
||||
RUN_TEST(eval);
|
||||
RUN_TEST(evalwithinwith);
|
||||
RUN_TEST(userobjectcompare);
|
||||
RUN_TEST(externalteardown);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -54,6 +54,59 @@ 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()
|
||||
{
|
||||
|
@ -51,6 +51,7 @@
|
||||
bool v8test_eval();
|
||||
bool v8test_evalwithinwith();
|
||||
bool v8test_userobjectcompare();
|
||||
bool v8test_externalteardown();
|
||||
|
||||
#endif // V8TEST_H
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user