Revision: 4805
Author: [email protected]
Date: Mon Jun  7 01:49:07 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=4805

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/heap-inl.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/include/v8.h        Fri Jun  4 04:49:44 2010
+++ /branches/bleeding_edge/include/v8.h        Mon Jun  7 01:49:07 2010
@@ -1122,11 +1122,13 @@

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


+typedef void (*ExternalStringDiposeCallback)
+    (String::ExternalStringResourceBase* resource);
+
+
 /**
  * A JavaScript number value (ECMA-262, 4.3.20)
  */
@@ -2461,6 +2471,15 @@
    */
   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.
    */
=======================================
--- /branches/bleeding_edge/src/api.cc  Fri Jun  4 04:49:44 2010
+++ /branches/bleeding_edge/src/api.cc  Mon Jun  7 01:49:07 2010
@@ -3690,6 +3690,14 @@
     }
   }
 }
+
+
+void V8::SetExternalStringDiposeCallback(
+    ExternalStringDiposeCallback callback) {
+  if (IsDeadCheck("v8::V8::SetExternalStringDiposeCallback()"))
+    return;
+  i::Heap::SetExternalStringDiposeCallback(callback);
+}


 void V8::SetCounterFunction(CounterLookupCallback callback) {
=======================================
--- /branches/bleeding_edge/src/heap-inl.h      Thu May 27 05:30:45 2010
+++ /branches/bleeding_edge/src/heap-inl.h      Mon Jun  7 01:49:07 2010
@@ -117,7 +117,14 @@
           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;
 }
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri Jun  4 04:57:01 2010
+++ /branches/bleeding_edge/src/heap.cc Mon Jun  7 01:49:07 2010
@@ -98,6 +98,8 @@
 // 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_;

=======================================
--- /branches/bleeding_edge/src/heap.h  Thu May 27 05:30:45 2010
+++ /branches/bleeding_edge/src/heap.h  Mon Jun  7 01:49:07 2010
@@ -689,6 +689,11 @@
   // Utility used with flag gc-greedy.
   static bool GarbageCollectionGreedyCheck();
 #endif
+
+  static void SetExternalStringDiposeCallback(
+      ExternalStringDiposeCallback callback) {
+    external_string_dispose_callback_ = callback;
+  }

   static void AddGCPrologueCallback(
       GCEpilogueCallback callback, GCType gc_type_filter);
@@ -1138,6 +1143,9 @@
   // 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 {
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Mon Jun  7 01:27:32 2010
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Mon Jun  7 01:49:07 2010
@@ -610,6 +610,71 @@
i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
   CHECK_EQ(1, TestAsciiResource::dispose_count);
 }
+
+
+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-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to