Index: src/api.cc |
=================================================================== |
--- src/api.cc (revision 1251) |
+++ src/api.cc (working copy) |
@@ -2440,22 +2440,58 @@ |
static void DisposeExternalString(v8::Persistent<v8::Value> obj, |
void* parameter) { |
- v8::String::ExternalStringResource* resource = |
- reinterpret_cast<v8::String::ExternalStringResource*>(parameter); |
- const size_t total_size = resource->length() * sizeof(*resource->data()); |
- i::Counters::total_external_string_memory.Decrement(total_size); |
- delete resource; |
+ i::ExternalTwoByteString* str = |
+ i::ExternalTwoByteString::cast(*Utils::OpenHandle(*obj)); |
+ |
+ // External symbols are deleted when they are pruned out of the symbol |
+ // table. Generally external symbols are not registered with the weak handle |
+ // callbacks unless they are upgraded to a symbol after being externalized. |
+ if (!str->IsSymbol()) { |
+ v8::String::ExternalStringResource* resource = |
+ reinterpret_cast<v8::String::ExternalStringResource*>(parameter); |
+ if (resource != NULL) { |
+ const size_t total_size = resource->length() * sizeof(*resource->data()); |
+ i::Counters::total_external_string_memory.Decrement(total_size); |
+ |
+ // The object will continue to live in the JavaScript heap until the |
+ // handle is entirely cleaned out by the next GC. For example the |
+ // destructor for the resource below could bring it back to life again. |
+ // Which is why we make sure to not have a dangling pointer here. |
+ str->set_resource(NULL); |
+ delete resource; |
+ } |
+ } |
+ |
+ // In any case we do not need this handle any longer. |
obj.Dispose(); |
} |
static void DisposeExternalAsciiString(v8::Persistent<v8::Value> obj, |
void* parameter) { |
- v8::String::ExternalAsciiStringResource* resource = |
- reinterpret_cast<v8::String::ExternalAsciiStringResource*>(parameter); |
- const size_t total_size = resource->length() * sizeof(*resource->data()); |
- i::Counters::total_external_string_memory.Decrement(total_size); |
- delete resource; |
+ i::ExternalAsciiString* str = |
+ i::ExternalAsciiString::cast(*Utils::OpenHandle(*obj)); |
+ |
+ // External symbols are deleted when they are pruned out of the symbol |
+ // table. Generally external symbols are not registered with the weak handle |
+ // callbacks unless they are upgraded to a symbol after being externalized. |
+ if (!str->IsSymbol()) { |
+ v8::String::ExternalAsciiStringResource* resource = |
+ reinterpret_cast<v8::String::ExternalAsciiStringResource*>(parameter); |
+ if (resource != NULL) { |
+ const size_t total_size = resource->length() * sizeof(*resource->data()); |
+ i::Counters::total_external_string_memory.Decrement(total_size); |
+ |
+ // The object will continue to live in the JavaScript heap until the |
+ // handle is entirely cleaned out by the next GC. For example the |
+ // destructor for the resource below could bring it back to life again. |
+ // Which is why we make sure to not have a dangling pointer here. |
+ str->set_resource(NULL); |
+ delete resource; |
+ } |
+ } |
+ |
+ // In any case we do not need this handle any longer. |
obj.Dispose(); |
} |
@@ -2475,6 +2511,24 @@ |
} |
+bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { |
+ if (IsDeadCheck("v8::String::MakeExternal()")) return false; |
+ if (this->IsExternal()) return false; // Already an external string. |
+ i::Handle <i::String> obj = Utils::OpenHandle(this); |
+ bool result = obj->MakeExternal(resource); |
+ if (result && !obj->IsSymbol()) { |
+ // Operation was successful and the string is not a symbol. In this case |
+ // we need to make sure that the we call the destructor for the external |
+ // resource when no strong references to the string remain. |
+ i::Handle<i::Object> handle = i::GlobalHandles::Create(*obj); |
+ i::GlobalHandles::MakeWeak(handle.location(), |
+ resource, |
+ &DisposeExternalString); |
+ } |
+ return result; |
+} |
+ |
+ |
Local<String> v8::String::NewExternal( |
v8::String::ExternalAsciiStringResource* resource) { |
EnsureInitialized("v8::String::NewExternal()"); |
@@ -2490,6 +2544,25 @@ |
} |
+bool v8::String::MakeExternal( |
+ v8::String::ExternalAsciiStringResource* resource) { |
+ if (IsDeadCheck("v8::String::MakeExternal()")) return false; |
+ if (this->IsExternal()) return false; // Already an external string. |
+ i::Handle <i::String> obj = Utils::OpenHandle(this); |
+ bool result = obj->MakeExternal(resource); |
+ if (result && !obj->IsSymbol()) { |
+ // Operation was successful and the string is not a symbol. In this case |
+ // we need to make sure that the we call the destructor for the external |
+ // resource when no strong references to the string remain. |
+ i::Handle<i::Object> handle = i::GlobalHandles::Create(*obj); |
+ i::GlobalHandles::MakeWeak(handle.location(), |
+ resource, |
+ &DisposeExternalAsciiString); |
+ } |
+ return result; |
+} |
+ |
+ |
Local<v8::Object> v8::Object::New() { |
EnsureInitialized("v8::Object::New()"); |
LOG_API("Object::New"); |