Hi Kent!
Here is the diff against 565cca4b737f28572230d88a42052ce5014294b9
you've requested. I had to do some changes. For example your version
of V8 doesn't even have that Foreign::foreign_address()
function that caused the segfault I wrote about earlier.
So I've changed it back to Foreign::address().
I also ran the tests, all of them passed.
Best regards,
Gabor Ballabas
----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.
diff --git a/include/v8.h b/include/v8.h
index 3ef4dd6..ac5a374 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1613,8 +1613,8 @@ class Object : public Value {
friend class v8::internal::Heap;
};
- V8EXPORT void SetExternalResource(ExternalResource *);
- V8EXPORT ExternalResource *GetExternalResource();
+ V8EXPORT void SetExternalResource(ExternalResource* resource);
+ V8EXPORT ExternalResource* GetExternalResource();
// Testers for local properties.
V8EXPORT bool HasOwnProperty(Handle<String> key);
diff --git a/src/api.cc b/src/api.cc
index 7d54252..5a8bb78 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1436,8 +1436,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
}
-bool ObjectTemplate::HasExternalResource()
-{
+bool ObjectTemplate::HasExternalResource() {
if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
"v8::ObjectTemplate::HasExternalResource()")) {
return 0;
@@ -1446,8 +1445,7 @@ bool ObjectTemplate::HasExternalResource()
}
-void ObjectTemplate::SetHasExternalResource(bool value)
-{
+void ObjectTemplate::SetHasExternalResource(bool value) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) {
return;
@@ -1459,7 +1457,8 @@ void ObjectTemplate::SetHasExternalResource(bool value)
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());
+ Utils::OpenHandle(this)->set_has_external_resource(
+ Utils::OpenHandle(this)->GetHeap()->undefined_value());
}
}
@@ -4057,14 +4056,15 @@ void v8::Object::SetPointerInInternalField(int index, void* value) {
}
-void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
+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)));
+ obj->SetExternalResourceObject(*isolate->factory()->NewForeign(
+ static_cast<i::Address>(reinterpret_cast<void*>(resource))));
}
if (!obj->IsSymbol()) {
isolate->heap()->external_string_table()->AddObject(*obj);
@@ -4072,13 +4072,15 @@ void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
}
-v8::Object::ExternalResource *v8::Object::GetExternalResource() {
+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));
+ 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());
+ return reinterpret_cast<v8::Object::ExternalResource*>(
+ i::Foreign::cast(value)->address());
} else {
return NULL;
}
diff --git a/src/heap-inl.h b/src/heap-inl.h
index bca57cb..371ff5a 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -231,25 +231,28 @@ void Heap::FinalizeExternalString(HeapObject* string) {
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();
+ *resource_addr = NULL;
}
-
- // Clear the resource pointer in the string.
- *resource_addr = NULL;
+
} else {
- JSObject *object = JSObject::cast(string);
- Object *value = object->GetExternalResourceObject();
+ 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));
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(
+ Internals::GetExternalPointerFromSmi(value));
} else if (value->IsForeign()) {
- resource = reinterpret_cast<v8::Object::ExternalResource*>(Foreign::cast(value)->address());
- }
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(
+ Foreign::cast(value)->address());
+ }
+
if (resource) {
- resource->Dispose();
+ resource->Dispose();
}
}
}
diff --git a/src/heap.cc b/src/heap.cc
index 53a0f27..10c10fe 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1099,8 +1099,9 @@ void Heap::Scavenge() {
}
-HeapObject* 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()) {
@@ -1132,7 +1133,8 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
if (target == NULL) continue;
- ASSERT(target->IsExternalString() || target->map()->has_external_resource());
+ ASSERT(target->IsExternalString() ||
+ target->map()->has_external_resource());
if (InNewSpace(target)) {
// String is still in new space. Update the table entry.
@@ -6367,15 +6369,15 @@ void ExternalStringTable::CleanUp() {
void ExternalStringTable::TearDown() {
- for (int i = 0; i < new_space_strings_.length(); ++i) {
+ 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]);
+ HeapObject* object = HeapObject::cast(new_space_strings_[i]);
if (!object->IsExternalString())
heap_->FinalizeExternalString(object);
}
- for (int i = 0; i < old_space_strings_.length(); ++i) {
+ 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]);
+ HeapObject* object = HeapObject::cast(old_space_strings_[i]);
if (!object->IsExternalString())
heap_->FinalizeExternalString(object);
}
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index bf0aab8..ad3f386 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1514,7 +1514,8 @@ class SymbolTableCleaner : public ObjectVisitor {
// Since no objects have yet been moved we can safely access the map of
// the object.
if (o->IsExternalString() ||
- (o->IsHeapObject() && HeapObject::cast(o)->map()->has_external_resource())) {
+ (o->IsHeapObject() &&
+ HeapObject::cast(o)->map()->has_external_resource())) {
heap_->FinalizeExternalString(HeapObject::cast(*p));
}
// Set the entry to null_value (as deleted).
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6a80c9c..eb97033 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1343,7 +1343,8 @@ 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()->has_external_resource()?1:0);
+ map()->inobject_properties() -
+ (map()->has_external_resource() ? 1 : 0);
}
@@ -1362,18 +1363,7 @@ Object* JSObject::GetInternalField(int index) {
}
-void JSObject::SetInternalField(int index, Object* value) {
- ASSERT(index < GetInternalFieldCount() && index >= 0);
- // 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);
- WRITE_FIELD(this, offset, value);
- WRITE_BARRIER(GetHeap(), this, offset, value);
-}
-
-
-void JSObject::SetExternalResourceObject(Object *value) {
+void JSObject::SetExternalResourceObject(Object* value) {
ASSERT(map()->has_external_resource());
int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
WRITE_FIELD(this, offset, value);
@@ -1381,15 +1371,27 @@ void JSObject::SetExternalResourceObject(Object *value) {
}
-Object *JSObject::GetExternalResourceObject() {
+Object *JSObject::GetExternalResourceObject() {
if (map()->has_external_resource()) {
- return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
+ return READ_FIELD(this, GetHeaderSize() +
+ kPointerSize * GetInternalFieldCount());
} else {
return GetHeap()->undefined_value();
}
}
+void JSObject::SetInternalField(int index, Object* value) {
+ ASSERT(index < GetInternalFieldCount() && index >= 0);
+ // 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);
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(GetHeap(), this, offset, 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.
@@ -2772,32 +2774,31 @@ bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
}
-void Map::set_has_external_resource(bool value) {
+void Map::set_named_interceptor_is_fallback(bool value)
+{
if (value) {
- set_bit_field(bit_field() | (1 << kHasExternalResource));
+ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
} else {
- set_bit_field(bit_field() & ~(1 << kHasExternalResource));
+ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback));
}
}
-bool Map::has_external_resource()
+bool Map::named_interceptor_is_fallback()
{
- return ((1 << kHasExternalResource) & bit_field()) != 0;
+ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
}
-
-void Map::set_named_interceptor_is_fallback(bool value)
-{
+
+void Map::set_has_external_resource(bool value) {
if (value) {
- set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
+ set_bit_field(bit_field() | (1 << kHasExternalResource));
} else {
- set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback));
+ set_bit_field(bit_field() & ~(1 << kHasExternalResource));
}
}
-bool Map::named_interceptor_is_fallback()
-{
- return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
+bool Map::has_external_resource() {
+ return ((1 << kHasExternalResource) & bit_field()) != 0;
}
diff --git a/src/objects.h b/src/objects.h
index c38d461..9918a92 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1760,8 +1760,9 @@ class JSObject: public JSReceiver {
inline Object* GetInternalField(int index);
inline void SetInternalField(int index, Object* value);
- inline void SetExternalResourceObject(Object *);
- inline Object *GetExternalResourceObject();
+ inline void SetExternalResourceObject(Object* value);
+ inline Object* GetExternalResourceObject();
+
// The following lookup functions skip interceptors.
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
@@ -4246,15 +4247,15 @@ 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();
-
// 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);
+ inline bool named_interceptor_is_fallback();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
@@ -4519,8 +4520,8 @@ 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;
+ static const int kNamedInterceptorIsFallback = 1;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -7565,7 +7566,8 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kConstructorOffset = TemplateInfo::kHeaderSize;
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
- static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
+ static const int kHasExternalResourceOffset =
+ kInternalFieldCountOffset + kPointerSize;
static const int kSize = kHasExternalResourceOffset + kPointerSize;
};
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 5081a64..3743b02 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -710,6 +710,179 @@ TEST(ExternalStringWithDisposeHandling) {
}
+class TestPoint {
+ public:
+ TestPoint(int x, int y)
+ : x_(x), y_(y) { }
+
+ int32_t x_, y_;
+};
+
+
+class TestPointResource : public v8::Object::ExternalResource {
+ public:
+ TestPointResource(TestPoint* tpoint, int* counter = NULL)
+ : tpoint_(tpoint), counter_(counter) {}
+
+ ~TestPointResource() {
+ delete tpoint_;
+ if (counter_ != NULL) ++*counter_;
+ }
+
+ TestPoint* tpoint_;
+ int* counter_;
+};
+
+
+static Handle<Value> GetTestPointX(Local<String>, const AccessorInfo& info) {
+ Local<Object> self = info.Holder();
+ TestPointResource* test_point_resource =
+ static_cast<TestPointResource*>(self->GetExternalResource());
+ CHECK(test_point_resource);
+ return v8::Int32::New(test_point_resource->tpoint_->x_);
+}
+
+
+static Handle<Value> GetTestPointY(Local<String>, const AccessorInfo& info) {
+ Local<Object> self = info.Holder();
+ TestPointResource* test_point_resource =
+ static_cast<TestPointResource*>(self->GetExternalResource());
+ CHECK(test_point_resource);
+ return v8::Int32::New(test_point_resource->tpoint_->y_);
+}
+
+
+THREADED_TEST(ExternalResource) {
+ int dispose_count = 0;
+ TestPoint* test_point = new TestPoint(3, 4);
+ TestPointResource* test_point_resource =
+ new TestPointResource(test_point, &dispose_count);
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<ObjectTemplate> resource_template = ObjectTemplate::New();
+ resource_template->SetHasExternalResource(true);
+ resource_template->SetAccessor(String::New("x"), GetTestPointX);
+ resource_template->SetAccessor(String::New("y"), GetTestPointY);
+ CHECK(resource_template->HasExternalResource());
+ Local<Object> resource_obj = resource_template->NewInstance();
+ resource_obj->SetExternalResource(test_point_resource);
+ CHECK_EQ(test_point_resource,
+ static_cast<TestPointResource*>(resource_obj->GetExternalResource()));
+ // There was some problem with InternalFieldCount() in an erlier version.
+ CHECK_EQ(0, resource_obj->InternalFieldCount());
+ CHECK_EQ(test_point->x_, resource_obj->Get(String::New("x"))->Int32Value());
+ CHECK_EQ(test_point->y_, resource_obj->Get(String::New("y"))->Int32Value());
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CHECK_EQ(0, dispose_count);
+ }
+ HEAP->CollectAllAvailableGarbage();
+ CHECK_EQ(1, dispose_count);
+}
+
+
+THREADED_TEST(ScavengeExternalResource) {
+ int dispose_count = 0;
+ TestPoint* test_point = new TestPoint(3, 4);
+ TestPointResource* test_point_resource =
+ new TestPointResource(test_point, &dispose_count);
+ bool in_new_space;
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<ObjectTemplate> resource_template = ObjectTemplate::New();
+ resource_template->SetHasExternalResource(true);
+ resource_template->SetAccessor(String::New("x"), GetTestPointX);
+ resource_template->SetAccessor(String::New("y"), GetTestPointY);
+ CHECK(resource_template->HasExternalResource());
+ Local<Object> resource_obj = resource_template->NewInstance();
+ resource_obj->SetExternalResource(test_point_resource);
+ i::Handle<i::JSObject> iobject = v8::Utils::OpenHandle(*resource_obj);
+ HEAP->CollectGarbage(i::NEW_SPACE);
+ in_new_space = HEAP->InNewSpace(*iobject);
+ CHECK(in_new_space || HEAP->old_data_space()->Contains(*iobject));
+ CHECK_EQ(0, dispose_count);
+ }
+ HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
+ CHECK_EQ(1, dispose_count);
+}
+
+
+class TestPointResourceWithDisposeControl: public TestPointResource {
+ public:
+ // Only used by non-threaded tests, so it can use static fields.
+ static int dispose_calls;
+ static int dispose_count;
+
+ TestPointResourceWithDisposeControl(TestPoint* tpoint, bool dispose)
+ : TestPointResource(tpoint, &dispose_count),
+ dispose_(dispose) { }
+
+ void Dispose() {
+ ++dispose_calls;
+ if (dispose_) delete this;
+ }
+
+ private:
+ bool dispose_;
+};
+
+
+int TestPointResourceWithDisposeControl::dispose_count = 0;
+int TestPointResourceWithDisposeControl::dispose_calls = 0;
+
+
+TEST(ExternalResourceWithDisposeHandling) {
+ TestPoint* test_point_one = new TestPoint(3, 4);
+
+ // Use a stack allocated external resource allocated object.
+ TestPointResourceWithDisposeControl::dispose_count = 0;
+ TestPointResourceWithDisposeControl::dispose_calls = 0;
+ TestPointResourceWithDisposeControl res_stack(test_point_one, false);
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<ObjectTemplate> resource_template = ObjectTemplate::New();
+ resource_template->SetHasExternalResource(true);
+ resource_template->SetAccessor(String::New("x"), GetTestPointX);
+ resource_template->SetAccessor(String::New("y"), GetTestPointY);
+ CHECK(resource_template->HasExternalResource());
+ Local<Object> resource_obj = resource_template->NewInstance();
+ resource_obj->SetExternalResource(&res_stack);
+
+ HEAP->CollectAllAvailableGarbage();
+ CHECK_EQ(0, TestPointResourceWithDisposeControl::dispose_count);
+ }
+ HEAP->CollectAllAvailableGarbage();
+ CHECK_EQ(1, TestPointResourceWithDisposeControl::dispose_calls);
+ CHECK_EQ(0, TestPointResourceWithDisposeControl::dispose_count);
+
+ // Use a heap allocated external resource allocated object.
+ TestPointResourceWithDisposeControl::dispose_count = 0;
+ TestPointResourceWithDisposeControl::dispose_calls = 0;
+ TestPoint* test_point_two = new TestPoint(5, 6);
+ TestPointResource* res_heap =
+ new TestPointResourceWithDisposeControl(test_point_two, true);
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<ObjectTemplate> resource_template = ObjectTemplate::New();
+ resource_template->SetHasExternalResource(true);
+ resource_template->SetAccessor(String::New("x"), GetTestPointX);
+ resource_template->SetAccessor(String::New("y"), GetTestPointY);
+ CHECK(resource_template->HasExternalResource());
+ Local<Object> resource_obj = resource_template->NewInstance();
+ resource_obj->SetExternalResource(res_heap);
+
+ HEAP->CollectAllAvailableGarbage();
+ CHECK_EQ(0, TestPointResourceWithDisposeControl::dispose_count);
+ }
+ HEAP->CollectAllAvailableGarbage();
+ CHECK_EQ(1, TestPointResourceWithDisposeControl::dispose_calls);
+ CHECK_EQ(1, TestPointResourceWithDisposeControl::dispose_count);
+}
+
+
THREADED_TEST(StringConcat) {
{
v8::HandleScope scope;
_______________________________________________
Qt-script mailing list
[email protected]
http://lists.qt.nokia.com/mailman/listinfo/qt-script