Commit 09acdc84 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Add an API to control the disposal of external string resources

A new callback have been added which - if set - will be called to dispose of external string resources passed from the embedder to the V8 engine.
Review URL: http://codereview.chromium.org/2645004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4805 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ff61618c
......@@ -1122,11 +1122,13 @@ class V8EXPORT String : public Primitive {
/**
* Creates a new external string using the data defined in the given
* resource. The resource is deleted when the external string is no
* longer live on V8's heap. The caller of this function should not
* delete or modify the resource. Neither should the underlying buffer be
* deallocated or modified except through the destructor of the
* external string resource.
* resource. When the external string is no longer live on V8's heap the
* resource will be disposed. If a disposal callback has been set using
* SetExternalStringDiposeCallback this callback will be called to dispose
* the resource. Otherwise, V8 will dispose the resource using the C++ delete
* operator. The caller of this function should not otherwise delete or
* modify the resource. Neither should the underlying buffer be deallocated
* or modified except through the destructor of the external string resource.
*/
static Local<String> NewExternal(ExternalStringResource* resource);
......@@ -1136,17 +1138,20 @@ class V8EXPORT String : public Primitive {
* will use the external string resource. The external string resource's
* character contents needs to be equivalent to this string.
* Returns true if the string has been changed to be an external string.
* The string is not modified if the operation fails.
* The string is not modified if the operation fails. See NewExternal for
* information on the lifetime of the resource.
*/
bool MakeExternal(ExternalStringResource* resource);
/**
* Creates a new external string using the ascii data defined in the given
* resource. The resource is deleted when the external string is no
* longer live on V8's heap. The caller of this function should not
* delete or modify the resource. Neither should the underlying buffer be
* deallocated or modified except through the destructor of the
* external string resource.
* resource. When the external string is no longer live on V8's heap the
* resource will be disposed. If a disposal callback has been set using
* SetExternalStringDiposeCallback this callback will be called to dispose
* the resource. Otherwise, V8 will dispose the resource using the C++ delete
* operator. The caller of this function should not otherwise delete or
* modify the resource. Neither should the underlying buffer be deallocated
* or modified except through the destructor of the external string resource.
*/
static Local<String> NewExternal(ExternalAsciiStringResource* resource);
......@@ -1156,7 +1161,8 @@ class V8EXPORT String : public Primitive {
* will use the external string resource. The external string resource's
* character contents needs to be equivalent to this string.
* Returns true if the string has been changed to be an external string.
* The string is not modified if the operation fails.
* The string is not modified if the operation fails. See NewExternal for
* information on the lifetime of the resource.
*/
bool MakeExternal(ExternalAsciiStringResource* resource);
......@@ -1245,6 +1251,10 @@ class V8EXPORT String : public Primitive {
};
typedef void (*ExternalStringDiposeCallback)
(String::ExternalStringResourceBase* resource);
/**
* A JavaScript number value (ECMA-262, 4.3.20)
*/
......@@ -2461,6 +2471,15 @@ class V8EXPORT V8 {
*/
static void RemoveMessageListeners(MessageCallback that);
/**
* Set a callback to be called when an external string is no longer live on
* V8's heap. The resource will no longer be needed by V8 and the embedder
* can dispose of if. If this callback is not set V8 will free the resource
* using the C++ delete operator.
*/
static void SetExternalStringDiposeCallback(
ExternalStringDiposeCallback that);
/**
* Sets V8 flags from a string.
*/
......
......@@ -3692,6 +3692,14 @@ void V8::RemoveMessageListeners(MessageCallback that) {
}
void V8::SetExternalStringDiposeCallback(
ExternalStringDiposeCallback callback) {
if (IsDeadCheck("v8::V8::SetExternalStringDiposeCallback()"))
return;
i::Heap::SetExternalStringDiposeCallback(callback);
}
void V8::SetCounterFunction(CounterLookupCallback callback) {
if (IsDeadCheck("v8::V8::SetCounterFunction()")) return;
i::StatsTable::SetCounterFunction(callback);
......
......@@ -117,7 +117,14 @@ void Heap::FinalizeExternalString(String* string) {
reinterpret_cast<byte*>(string) +
ExternalString::kResourceOffset -
kHeapObjectTag);
delete *resource_addr;
// Dispose of the C++ object.
if (external_string_dispose_callback_ != NULL) {
external_string_dispose_callback_(*resource_addr);
} else {
delete *resource_addr;
}
// Clear the resource pointer in the string.
*resource_addr = NULL;
}
......
......@@ -98,6 +98,8 @@ size_t Heap::code_range_size_ = 0;
// set up by ConfigureHeap otherwise.
int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
ExternalStringDiposeCallback Heap::external_string_dispose_callback_ = NULL;
List<Heap::GCPrologueCallbackPair> Heap::gc_prologue_callbacks_;
List<Heap::GCEpilogueCallbackPair> Heap::gc_epilogue_callbacks_;
......
......@@ -690,6 +690,11 @@ class Heap : public AllStatic {
static bool GarbageCollectionGreedyCheck();
#endif
static void SetExternalStringDiposeCallback(
ExternalStringDiposeCallback callback) {
external_string_dispose_callback_ = callback;
}
static void AddGCPrologueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
static void RemoveGCPrologueCallback(GCEpilogueCallback callback);
......@@ -1138,6 +1143,9 @@ class Heap : public AllStatic {
// any string when looked up in properties.
static String* hidden_symbol_;
static ExternalStringDiposeCallback
external_string_dispose_callback_;
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
struct GCPrologueCallbackPair {
......
......@@ -612,6 +612,71 @@ THREADED_TEST(ScavengeExternalAsciiString) {
}
static int dispose_count = 0;
static void DisposeExternalStringCount(
String::ExternalStringResourceBase* resource) {
dispose_count++;
}
static void DisposeExternalStringDeleteAndCount(
String::ExternalStringResourceBase* resource) {
delete resource;
dispose_count++;
}
TEST(ExternalStringWithResourceDisposeCallback) {
const char* c_source = "1 + 2 * 3";
// Set an external string collected callback which does not delete the object.
v8::V8::SetExternalStringDiposeCallback(DisposeExternalStringCount);
// Use a stack allocated external string resource allocated object.
dispose_count = 0;
TestAsciiResource::dispose_count = 0;
TestAsciiResource res_stack(i::StrDup(c_source));
{
v8::HandleScope scope;
LocalContext env;
Local<String> source = String::NewExternal(&res_stack);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(1, dispose_count);
CHECK_EQ(0, TestAsciiResource::dispose_count);
// Set an external string collected callback which does delete the object.
v8::V8::SetExternalStringDiposeCallback(DisposeExternalStringDeleteAndCount);
// Use a heap allocated external string resource allocated object.
dispose_count = 0;
TestAsciiResource::dispose_count = 0;
TestAsciiResource* res_heap = new TestAsciiResource(i::StrDup(c_source));
{
v8::HandleScope scope;
LocalContext env;
Local<String> source = String::NewExternal(res_heap);
Local<Script> script = Script::Compile(source);
Local<Value> value = script->Run();
CHECK(value->IsNumber());
CHECK_EQ(7, value->Int32Value());
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(1, dispose_count);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
THREADED_TEST(StringConcat) {
{
v8::HandleScope scope;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment