Update V8

Change-Id: I7a9da7dbb2116a441788407d60ed10155cded941
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
This commit is contained in:
Aaron Kennedy 2011-10-11 15:06:25 +10:00 committed by Qt by Nokia
parent 4dc25c1f29
commit 7dc5973bf1
24 changed files with 1567 additions and 2702 deletions

2
src/3rdparty/v8 vendored

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

View File

@ -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

View File

@ -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

View File

@ -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);

View 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

View File

@ -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

View File

@ -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() {
}
}

View File

@ -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, &not_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, &not_user_equal);
@ -139,25 +143,26 @@ index a2626bf..749c9be 100644
+
+ __ bind(&not_user_equal);
+ }
+
+
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
@@ -5802,10 +5832,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ tst(r2, Operand(kSmiTagMask));
__ b(eq, &miss);
@@ -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, &not_user_equal);
+ __ test(edx, Immediate(kSmiTagMask));
@ -218,10 +223,10 @@ index afa599e..0964ab9 100644
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &not_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(&not_user_equal);
+ }
+
+
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
@@ -5592,8 +5626,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
// 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, &not_user_equal);
+ __ JumpIfSmi(rdx, &not_user_equal);
+
@ -446,10 +505,10 @@ index d923494..10b9b56 100644
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &not_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(&not_user_equal);
+ }
+
// The compare stub returns a positive, negative, or zero 64-bit integer
// value in rax, corresponding to result of comparing the two inputs.
// NOTICE! This code is only reached after a smi-fast-case check, so
@@ -4471,8 +4502,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
// 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);

View File

@ -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);

View File

@ -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") \

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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(-)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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()
{

View File

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