From 7dc5973bf12919d2d35230844beabe558d4faa00 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 11 Oct 2011 15:06:25 +1000 Subject: Update V8 Change-Id: I7a9da7dbb2116a441788407d60ed10155cded941 Reviewed-by: Kent Hansen --- ...0003-Generalize-external-object-resources.patch | 595 +++++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 src/v8/0003-Generalize-external-object-resources.patch (limited to 'src/v8/0003-Generalize-external-object-resources.patch') diff --git a/src/v8/0003-Generalize-external-object-resources.patch b/src/v8/0003-Generalize-external-object-resources.patch new file mode 100644 index 0000000000..658a09126a --- /dev/null +++ b/src/v8/0003-Generalize-external-object-resources.patch @@ -0,0 +1,595 @@ +From be5bc4e5ea15dd74c2753c30c25a4660598274c3 Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy +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 key); + V8EXPORT bool HasRealNamedProperty(Handle 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 New(Handle 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 obj = Utils::OpenHandle(this); ++ if (CanBeEncodedAsSmi(resource)) { ++ obj->SetExternalResourceObject(EncodeAsSmi(resource)); ++ } else { ++ obj->SetExternalResourceObject(*isolate->factory()->NewForeign(static_cast((void *)resource))); ++ } ++ if (!obj->IsSymbol()) { ++ isolate->heap()->external_string_table()->AddObject(*obj); ++ } ++} ++ ++ ++v8::Object::ExternalResource *v8::Object::GetExternalResource() { ++ i::Handle obj = Utils::OpenHandle(this); ++ i::Object* value = obj->GetExternalResourceObject(); ++ if (value->IsSmi()) { ++ return reinterpret_cast(i::Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsForeign()) { ++ return reinterpret_cast(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 Factory::CreateApiFunction( + Handle construct_stub = isolate()->builtins()->JSConstructStubApi(); + + int internal_field_count = 0; ++ bool has_external_resource = false; ++ + if (!obj->instance_template()->IsUndefined()) { + Handle instance_template = + Handle( + 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 Factory::CreateApiFunction( + + Handle map = Handle(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( +- reinterpret_cast(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( ++ reinterpret_cast(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(Internals::GetExternalPointerFromSmi(value)); ++ } else if (value->IsForeign()) { ++ resource = reinterpret_cast(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(last - start)); ++ external_string_table_.ShrinkNewObjects(static_cast(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 + -- cgit v1.2.3